TL;DR: Enabling CloudKit sync is easy, but keeping it stable is difficult. The vast majority of sync errors following model adjustments stem from violating hard physical limitations of the data model. It is crucial to adhere to these rules during the design phase.
When enabling CloudKit synchronization for Core Data or SwiftData, the distributed nature of CloudKit imposes much stricter requirements on the local data model (Schema) than a purely local database. If these limitations are not fully considered during the modeling phase, subsequent adjustments can be incredibly painful.
Mandatory Data Model Rules
The following rules are compulsory. Violating any of them will result in sync failures or application crashes.
1. No Unique Constraints
CloudKit does not support atomic uniqueness checks across devices.
- Core Data: Do not configure
Unique constraintsin the Entity Configuration. - SwiftData: Do not use the
@Attribute(.unique)macro on properties.
2. Attributes Must Be Optional or Have Defaults
CloudKit needs to handle “partial data” synchronization scenarios.
- Forbidden: Non-Optional attributes without a default value.
- Allowed:
- Optional types (
?). - Non-Optional types with a Default Value.
- Optional types with a Default Value.
- Optional types (
3. Type Limitations
- Forbidden: Using the Core Data
Undefinedtype.
4. Strict Relationship Requirements
This is the most common source of errors:
- Must Be Optional: All Relationships must be marked as
Optional. - Must Have Inverse: All Relationships must have an
Inverserelationship defined. While SwiftData macros often handle this automatically, it must be specified manually in the Core Data editor. - No ‘Deny’ Delete Rules: The Delete Rule cannot be set to
Deny. - No Ordered Relationships: You cannot check
Ordered(Arrangement) in Core Data. SwiftData does not support this option either.
Migration Strategy: Add-Only
Once CloudKit is enabled, schema changes are heavily restricted. You are effectively limited to Lightweight Migration.
Strict Modification Limits
Once your app is live (and the Schema has been pushed to the Production environment), you must adhere to the “Add-Only, No-Delete, No-Change” principle:
- No Deletions: Do not delete existing Entities or Attributes. Even if you no longer use them, keep them in the model definition.
- No Renaming: Do not rename Entities or Attributes. CloudKit interprets a rename as “deleting the old one and adding a new one,” resulting in data loss for the old field and sync inconsistencies.
- No Type Changes: Do not change the data type of an attribute (e.g., changing a
Stringto anInt).
Recommended Practices
If you must modify the model:
- Add New Attributes: This is the safest approach.
- Deprecate Old Attributes: Stop using the old attributes in your code, but leave the model definition intact.