Best Practices for Binary Data (“Allows External Storage”) in Core Data with CloudKit Sync

Hello Apple Team,

We’re building a CloudKit-enabled Core Data app and would like clarification on the behavior and performance characteristics of Binary Data attributes with “Allows External Storage” enabled when used with NSPersistentCloudKitContainer.

Initially, we tried storing image files manually on disk and only saving the metadata (file URLs, dimensions, etc.) in Core Data. While this approach reduced the size of the Core Data store, it introduced instability after app updates and broke sync between devices. We would prefer to use the official Apple-recommended method and have Core Data manage image storage and CloudKit syncing natively.

Specifically, we’d appreciate guidance on the following:

When a Binary Data attribute is marked as “Allows External Storage”, large image files are stored as separate files on device rather than inline in the SQLite store.

How effective is this mechanism in keeping the Core Data store size small on device?

Are there any recommended size thresholds or known limits for how many externally stored blobs can safely be managed this way?

How are these externally stored files handled during CloudKit sync?

Does each externally stored Binary Data attribute get mirrored to CloudKit as a CKAsset?

Does external storage reduce the sync payload size or network usage, or is the full binary data still uploaded/downloaded as part of the CKAsset?

Are there any bandwidth implications for users syncing via their private CloudKit database, versus developer costs in the public CloudKit database?

Is there any difference in CloudKit or Core Data behavior when a Binary Data attribute is managed this way versus manually storing image URLs and handling the file separately on disk?

Our goal is to store user-generated images efficiently and safely sync them via CloudKit, without incurring excessive local database bloat or CloudKit network overhead.

Any detailed guidance or internal performance considerations would be greatly appreciated.

Thank you, Paul Barry Founder & Lead Developer — Boat Buddy / Vessel Buddy iOS App Archipelago Environmental Solutions Inc.

When a Binary Data attribute is marked as “Allows External Storage”, large image files are stored as separate files on the device rather than inline in the SQLite store.

That is correct. There is a threshold when the data will get stored in external files next to the SQLite database, similar to the approach that you described with URLs, but that process is managed by CoreData and transparent to your app you.

How effective is this mechanism in keeping the Core Data store size small on the device?

It depends on what you mean by the store. The SQLite file will be smaller, but the files are still stored on the device.

Are there any recommended size thresholds or known limits for how many externally stored blobs can safely be managed this way?

There is in general no limit. CoreData will decide when it's worth using an external file. If the blob you are storing is only a few bytes, it'll remain inline. If you expect to have a lot of assets, you should consider how you expect your app to behave when the user is low on disk space. When fetching they will be loaded into memory, so if you need to load a lot of large image assets you will likely run into memory limits. See Making changes to reduce memory use specifically the "Optimize image assets" section.

How are these externally stored files handled during CloudKit sync? Does each externally stored Binary Data attribute get mirrored to CloudKit as a CKAsset?

CloudKit syncing is a separate process. CloudKit has its own threshold values. This is not controlled by the allowsExternalBinaryDataStorage.

https://developer.apple.com/documentation/coredata/reading-cloudkit-records-for-core-data has an overview of when String/Data/Transformable attributes will be stored as CKAsset.

Is there any difference in CloudKit or Core Data behavior when a Binary Data attribute is managed this way versus manually storing image URLs and handling the file separately on disk? Our goal is to store user-generated images efficiently and safely sync them via CloudKit, without incurring excessive local database bloat or CloudKit network overhead.

When you store URLs or other references, you will need to handle the upload/download of these files, which is extra work - but it gives you more flexibility if you only want to keep a subset of the assets on the device.

It's hard to give concrete advice on some without some more context, but hopefully this helps.

Some things you might want to consider when making this decision:

  • How much data do you expect to be in these stores? If it's too large you might want to consider making them part of the store and store references as references you store yourself.
  • How do you expect your app to behave when the user is low on disk space? If you keep your assets outside of the CoreData store, Reducing your app’s disk usage can give you a good overview.
  • Do you expect all assets to be downloaded, or do you want to load them if needed? There are UI and bandwidth considerations.
  • If you want to go the route that you manually manage these assets, I recommend reviewing CoreData's persistent history feature, as an option to keep your custom asset storage in sync with your CoreData store.
Best Practices for Binary Data (“Allows External Storage”) in Core Data with CloudKit Sync
 
 
Q