Core Data Migration Strategy: store relocation, schema changes and CloudKit adoption in a single release?

I am planning a Core Data migration for a macOS app targeting macOS 12 and later and I would appreciate guidance on structuring the rollout to minimise risk.

Context

The app currently uses a SQLite store located at:

~/Library/Containers/com.company.AppName/Data/Library/Application Support/AppName

I want to:

  1. Relocate the persistent store to an app group container: ~/Library/Group Containers/group.com.company.AppName
  2. Perform schema migration, including:
    • Renaming attributes
    • Deleting attributes
    • Using a custom NSEntityMigrationPolicy subclass
  3. Adopt iCloud sync using NSPersistentCloudKitContainer
  4. Potentially leverage staged migration (macOS 14+)

Additionally, I intend to port the app to iOS, so the end state needs to support an app group container and CloudKit with the latest schema from the outset.

Questions

  1. Store relocation vs schema migration

    • Is it advisable to perform store relocation and schema migration in a single step, or should these be separate releases?
    • If combined, are there pitfalls when moving the SQLite file and running a migration in the same launch cycle?
  2. Custom migration policy

    • Any best practices for structuring NSEntityMigrationPolicy when also relocating the store?
    • Should migration policies assume the store has already been moved, or handle both concerns?
  3. Staged migration (macOS 14+)

    • Is staged migration worth adopting when still supporting macOS 12–13?
    • Would you gate it conditionally, or avoid it entirely for consistency?
  4. CloudKit adoption

    • Is introducing NSPersistentCloudKitContainer in the same release as the above migrations too risky?
    • Are there known issues when enabling CloudKit immediately after a migration?
  5. Release strategy

    • Would you recommend:
      • A single release handling everything
      • Two phases: (1) store & schema migration, (2) CloudKit
      • Or three phases: store relocation → schema migration → CloudKit

Goal

I want a smooth, reliable transition without data loss or duplication, particularly for existing users with non-trivial datasets.

Any insights, practical experience, or recommended sequencing strategies would be very helpful.

Given that you'd move the Core Data store to a group container, I'd assume that the store will be shared across different processes, such as your main app and its extension (a widget, for example). In that case, I'd like to start with pointing you the following threads:

These threads made it clear that:

  • After a user installed your new version app, depending on what extension you have, the app and extension can open and migrate the store simultaneously, and so you will need to implement a mechanism to make sure that the store is only migrated once.

  • Consider having your main app in charge of the the synchronization, as discussed in Avoid synchronizing a store with multiple persistent containers.

Now to your questions:

Store relocation vs schema migration Is it advisable to perform store relocation and schema migration in a single step, or should these be separate releases? If combined, are there pitfalls when moving the SQLite file and running a migration in the same launch cycle?

Combining relocation and migration is fine to me. I'd consider the following flow in your app's launch session:

  1. Load the store with your new version model to your Core Data stack, which kicks off the migration.

  2. After the migration is successfully done, copy the migrated store to your target folder using replacePersistentStore(at:destinationOptions:withPersistentStoreFrom:sourceOptions:type:).

  3. Remove the orginal store using destroyPersistentStore(at:type:options:).

Custom migration policy Any best practices for structuring NSEntityMigrationPolicy when also relocating the store? Should migration policies assume the store has already been moved, or handle both concerns?

I don't think NSEntityMigrationPolicy relies on the store location. Also, in the flow mentioned above, your main app does the migration before relocating the store.

Staged migration (macOS 14+) Is staged migration worth adopting when still supporting macOS 12–13? Would you gate it conditionally, or avoid it entirely for consistency?

Your choice. If you choose to conditionally use staged migration, be sure to test your app with different OS versions.

CloudKit adoption Is introducing NSPersistentCloudKitContainer in the same release as the above migrations too risky? Are there known issues when enabling CloudKit immediately after a migration? Release strategy Would you recommend: A single release handling everything Two phases: (1) store & schema migration, (2) CloudKit Or three phases: store relocation → schema migration → CloudKit

Adding CloudKit synchronization to your app introduces quite a bit more complexity, and so your two-phase strategy seems to be reasonable to me.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Core Data Migration Strategy: store relocation, schema changes and CloudKit adoption in a single release?
 
 
Q