How to migrate your persistent store from one location to another

Sometimes you need to change your NSPersistentStore file from one location to another. Or you want to add other options that the old store didn’t have (for example, add iCloud or turn an XML store into an SQLite store). In those cases you can migrate the current store.

Typically this is done by leaving the existing store as is, creating a new store with new properties. Then we’ll tell the NSPersistentStoreCoordinator about our plan, and he’ll swap out the store for us.

Here’s an example: I’ve created a Master/Detail Test App with Core Data and added a few records. All looks good. My persistent store was created by default like this – as provided by the template in AppDelegate.m:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"OldStore.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    return _persistentStoreCoordinator;

Now I’d like to change the location of the store to a new URL. While I’m at it I could add a new options dictionary – but I won’t show that here, because I’m pretty sure you know how that works 😉

Here’s a method I’m using for the migration:

- (void)migrateStore {

    // grab the current store
    NSPersistentStore *currentStore = self.persistentStoreCoordinator.persistentStores.lastObject;
    // create a new URL
    NSURL *newStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"NewStore.sqlite"];
    // setup new options dictionary if necessary
    // migrate current store to new URL
    [self.persistentStoreCoordinator migratePersistentStore:currentStore toURL:newStoreURL options:nil withType:NSSQLiteStoreType error:nil];

You can check if the migration has worked by writing out the URL before and after the migration. At this point the old store is no longer in use. If you’d like to go back it it at any time, simply perform another migration.

Demo Project

I’ve added a demo project on GitHub which demonstrates this:

21 thoughts on “How to migrate your persistent store from one location to another

  1. In the – (NSPersistentStoreCoordinator *)persistentStoreCoordinator { I am checking for the iCloud File and if it is not there I am calling the migrateStore. But it looks like it runs in a loop and it is never migrated. Should I be doing this somewhere else?


    (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    // iCloud
    // Check if the sqlite file has been migrated to iCloud
    NSString *storeFileiCloud = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @”Dailybook-iCloud.sqlite”];
    if (![[NSFileManager defaultManager] fileExistsAtPath:storeFileiCloud isDirectory:NO]) {
    [self migrateStore];


    // iCloud

    (void)migrateStore {

    // grab the current store
    NSPersistentStore *currentStore = self.persistentStoreCoordinator.persistentStores.lastObject;

    // create a new URL
    //NSURL *newStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@”NewStore.sqlite”];
    NSURL *newStoreURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent: @”Dailybook-iCloud.sqlite”]];

    // setup new options dictionary if necessary
    NSDictionary *options =
    //,NSPersistentStoreUbiquitousContentURLKey:@”ChangeLogs” // Optional since iOS7

    // migrate current store to new URL
    NSError *error;
    if (![self.persistentStoreCoordinator_ migratePersistentStore:currentStore toURL:newStoreURL options:options withType:NSSQLiteStoreType error:&error]) {
    NSLog(@”Error: %@”, error);
    NSLog(@”DONE Migrating”);


  2. Check the result in the if statement and see if it reports the existence of your store file correctly.

    I think there may be flaw in the way you’re constructing the file path. Assuming the applicationDocumentsDirectory method from a recent template, it returns an NSURL. Here’s how I would check for the existence of that file:

    NSURL *storeFile = [[self applicationDocumentsDirectory]URLByAppendingPathComponent:@"NewStore.sqlite"];
    if ([[NSFileManager defaultManager]fileExistsAtPath:storeFile.path isDirectory:NO]) {
        NSLog(@"The file does exist");
    } else {
        NSLog(@"The file does NOT exist");
    1. 🙂 This is an old Universal Template where the applicationDocumentsDirectory reruns a NSString (- (NSString *)applicationDocumentsDirectory)

      So far the if statement is working correctly. I was worried if I should not be calling the migrate from inside the persistentStoreCoordinator or I am calling it from the wrong position.

      I checked and the below currentStores is nil.

      // grab the current store
      NSPersistentStore *currentStore = persistentStoreCoordinator_.persistentStores.lastObject;


      1. In that case you’re calling the if statement too early. The persistent store coordinator needs to finish setting everything up first, only then can you call the migrate method – otherwise there is no store to migrate.

        1. Should have thought of that, I was calling it too early.

          I am now working on the below error: Something goes wrong with the migration.

          Error: Error Domain=NSCocoaErrorDomain Code=133000 “The operation couldn’t be completed. (Cocoa error 133000.)” UserInfo=0x1126e4b0 {NSUnderlyingException=Referential integrity problem found during migratePersistentStore:toURL:options:withType:error: CoreData could not fulfill a fault for ‘0x11279970 ‘}


  3. I am creating a new Sample Project like the one you used. Where did you call the migrateStore procedure? I would like to duplicate what you did.

    Since my Universal Project is so old I am thinking of re-creating the project with the latest template, get that working then I will add all my screens and logic 🙂 Huge job…

    Thank you.

      1. The NSCocoaErrorDomain Code=133000 Referential integrity problem error (from previous thread), this is being caused because of some corruption/broken relationships in my big test database. This obviously is something to worry about when a real user might run into this.

        For my testing I started with a fresh install without any existing data. Then added a bunch of records, did the migrate. Deleted the database and iCloud brought down the records just fine.

        Wanted to update you and this was the cause of my issue. Which at this point I am going to look at what I can do at runtime to check users SQLite file and try to fix/vacum/… the db before migrating.

        Thanks for all of your help.

        ps: WWDC has been a massive brain food, so much to sync in.

        1. Thanks for the update, I’m really glad the engineers could help you at WWDC. I’m ploughing through the session videos at home, and I love some of the new frameworks (like CloudKit) and the way Xcode is going. I even like Swift and think it’ll make code more readable – but at the same time there’s so much to learn (again) that it’s making my head hurt…

  4. HI Jay – absolutely love your posts and I really commend you on your hard work here. Seriously, I would pay much more than I did for a membership with access to your full videos, because it’s immense helpful!

    On that note, I followed your excellent tutorial ( on getting iCloud setup with Core Data and I’ve been battling with this for a few weeks now. My app is core data ready in the App Store but I’ve developing the iCloud version and so, for all existing customers, data has to be migrated across (if they’re using iCloud on the device of course).

    One thing I’m struggling with is the migration. In your github code and even in here, you’re talking about calling the migration method from the applicationDidFInishLaunchingWithOptions, which is all well and good; that makes sense to me. However, if the user runs the app again, or every subsequent time they run the app, isn’t it going to “migrate” again, with that method?

    What I essentially want is:
    1) App store App with Data
    2) Update to iCloud enabled version
    3) If iCloud + if Data in fallback store
    4) Migrate to iCloud
    5) Every subsequent launch, don’t migrate the data again, simply use the iCloud version (if available) or revert to fallback store (if offline), etc.

    I know I’m close, but am I missing something really simple?

    Thanks Jay,
    Best regards,

    1. Hi Amit,

      great to hear the site and the videos are helpful – especially given that I just had to resolve a dispute with a very unhappy customer 😉

      You’re very close indeed – all you’re missing is a test to see if a migration is necessary. You can do this by either checking your version number from the bundle (if it’s lower than 1.3 then the app needs a migration), or a value in the user defaults (if it’s set, no migration is necessary, and if it is, your app saved this value after the migration). Let me know if this makes sense, I’m happy to post some code to demonstrate this.

      1. Hi Jay – thanks so much for the amazingly prompt reply. You’re becoming one of my favourite people, ever 🙂 and disputes are no fun.. but you have me as a customer for life!

        Ahh man – that makes so much sense in both cases. I am kind of favouring the second approach, which is to set a flag in the user defaults when the migration has completed and to check that each and every time. I’d say that seems like it makes the most sense to me because I can some complexities with version numbers that would make me want to lose my mind, down the road.

        I can see this theoretically, but please could I potentially take you up on that offer of a little code to demonstrate how this would work? I’m still not an expert in coding (apologies for the questions), but I’m getting there 🙂 I’ve set a ton of user defaults in my code, so I’m cool with that, just not sure with exactly where to set it and what to set.. etc..

        Thanks again Jay!

  5. Hi Jay,

    Thanks for this useful article and sample code. However, there’s one thing that I struggle with. You write: ‘At this point the old store is no longer in use. If you’d like to go back it it at any time, simply perform another migration.’

    How can I migrate back to the old store? I understand that there’s still a store at the old location, but this store is no longer a store that is associated with the persistentStoreCoordinator. It’s just a couple of files (the sqlite file, the wal file and the shared memory file). The migratePersistentStore method takes a NSPersistentStore as an argument, so how can I make the old store files a NSPersistentstore object again and pass this into the method?

    I tried persistentStoreForURL: but that returns nil (the coordinator doesn’t have a persistentStore at the old url anymore).

    For clearness: I’m not trying to migrate the current store back to the old location. I’m trying to migrate the old store back into business.

    Any help is very much appreciated.


    1. Hi Joost,

      if you want to bring the old store back, and basically switch out one store for the other, then migration is not what you’re looking for. Instead you need to remove the current store from the coordinator, add the old store, and then fetch your data again.

      I’ve explained something similar here: In that example I’m deleting the old store and replace it with a new one in a running app. You can adapt this approach to read in data from an existing store instead of deleting it.

Leave a Reply