Migrating a SwiftUI iOS App from Core Data to Realm
Rate this tutorial
Porting an app that's using Core Data to Realm is very simple. If you
have an app that already uses Core Data, and have been considering the
move to Realm, this step-by-step guide is for you! The way that your
code interacts with Core Data and Realm is very different depending on
whether your app is based on SwiftUI or UIKit—this guide assumes SwiftUI
(a UIKit version will come soon.)
You're far from the first developer to port your app from Core Data to
Realm, and we've been told many times that it can be done in a matter of
hours. Both databases handle your data as objects, so migration is
usually very straightforward: Simply take your existing Core Data code
and refactor it to use the Realm
SDK.
After migrating, you should be thrilled with the ease of use, speed, and
stability that Realm can bring to your apps. Add in MongoDB Realm
Sync and you can share the same
data between iOS, Android, desktop, and web apps.
This article was updated in July 2021 to replace
objc
and dynamic
with the @Persisted
annotation that was introduced in Realm-Cocoa
10.10.0.This guide assumes that your app is written in Swift and built on
SwiftUI rather than UIKit.
To use Realm, you need to include Realm's Swift SDK
(Realm-Cocoa) in your Xcode
project. The simplest method is to use the Swift Package Manager.
In Xcode, select "File/Swift Packages/Add Package Dependency...". The
package URL is https://github.com/realm/realm-cocoa:

You can keep the default options and then select both the "Realm" and
"RealmSwift" packages.
First things first. If your app is currently using Core Data, you'll
need to work out which parts of your codebase include Core Data code.
These will need to be refactored. Fortunately, there's a handy way to do
this. While you could manually perform searches on the codebase looking
for the relevant code, a much easier solution is to simply delete the
Core Data import statements at the top of your source files:
Once this is done, every line of code implementing Core Data will throw
a compiler error, and then it's simply a matter of addressing each
compiler error, one at a time.
Not everyone (including me) likes the idea of not being able to build a
project until every part of the port has been completed. If that's you,
I'd suggest this approach:
- Leave the old code there for now.
- Add a new model, adding
Realm
to the end of each class. - Work through your views to move them over to your new model.
- Check and fix build breaks.
- Remove the
Realm
from your model names using the Xcode refactoring feature. - Check and fix build breaks.
- Find any files that still
import CoreData
and either remove that line or the entire file if it's now obsolete. - Check and fix build breaks.
- Migrate existing user data from Core Data to Realm if needed.
- Remove the original model code.
In Core Data, changes to model objects are made against a managed object
context object. Managed object context objects are created against a
persistent store coordinator object, which themselves are created
against a managed object model object.
Suffice to say, before you can even begin to think about writing or
reading data with Core Data, you usually need to have code somewhere in
your app to set up these dependency objects and to expose Core Data's
functionality to your app's own logic. There will be a sizable chunk of
"setup" Core Data code lurking somewhere.
When you're switching to Realm, all of that code can go.
In Realm, all of the setting up is done on your behalf when you access a
Realm object for the first time, and while there are options to
configure it—such as where to place your Realm data file on disk—it's
all completely optional.
Your Realm schema will be defined in code by defining your Realm Object
classes. There is no need for
.xcdatamodel
files when working with
Realm and so you can remove those Core Data files from your project.In Core Data, the bread-and-butter class that causes subclassed model
objects to be persisted is
NSManagedObject
. The classes for these
kinds of objects are pretty much standard:Converting these managed object subclasses to Realm is really simple:
Note that top-level objects inherit from
Object
, but objects that only
exist within higher-level objects inherit from EmbeddedObject
.Creating a new object in Core Data and then later modifying it is
relatively trivial, only taking a few lines of code.
Adding an object to Core Data must be done using a
NSManagedObjectContext
. This context is available inside a SwiftUI
view through the environment:That context can then be used to save the object to Core Data:
Realm requires that writes are made within a transaction, but the Realm
Swift SDK hides most of that complexity when you develop with SwiftUI.
The current Realm is made available through the SwiftUI environment and
the view can access objects in it using the
@ObserveredResults
property wrapper:A new object can then be stored in the Realm:
The Realm Swift SDK also hides the transactional complexity behind
making updates to objects already stored in Realm. The
@ObservedRealmObject
property wrapper is used in the same way as
@ObservedObject
—but for Realm managed objects:To benefit from the transparent transaction functionality, make sure
that you use the
@ObservedRealmObject
property wrapper as you pass
Realm objects down the view hierarchy.If you find that you need to directly update an attribute within a Realm
object within a view, then you can use this syntax to avoid having to
explicitly work with Realm transactions (where
reminder
is an
@ObservedRealmObject
):In its most basic implementation, Core Data uses the concept of fetch
requests in order to retrieve data from disk. A fetch can filter and
sort the objects:
The equivalent code for such a query using Realm is very similar, but it
uses the
@ObservedResults
property wrapper rather than FetchRequest
:Once all of your code has been migrated to Realm, there's one more
outstanding issue: How do you migrate any production data that users may
already have on their devices out of Core Data and into Realm?
This can be a very complex issue. Depending on your app's functionality,
as well as your users' circumstances, how you go about handling this can
end up being very different each time.
We've seen two major approaches:
- Once you've migrated your code to Realm, you can re-link the Core Data framework back into your app, use raw NSManagedObject objects to fetch your users' data from Core Data, and then manually pass it over to Realm. You can leave this migration code in your app permanently, or simply remove it after a sufficient period of time has passed.
- If the user's data is replaceable—for example, if it is simply cached information that could be regenerated by other user data on disk—then it may be easier to simply blow all of the Core Data save files away, and start from scratch when the user next opens the app. This needs to be done with very careful consideration, or else it could end up being a bad user experience for a lot of people.
As with Core Data, your SwiftUI previews can add some data to Realm so
that it's rendered in the preview. However, with Realm it's a lot easier
as you don't need to mess with contexts and view contexts:
Now that your application data is stored in Realm, you have the option
to sync that data to other devices (including Android) using MongoDB
Realm Sync. That same data is
then stored in Atlas where it can be queried by web applications via
GraphQL or Realm's web
SDK.
This enhanced functionality is beyond the scope of this guide, but you
can see how it can be added by reading the
Building a Mobile Chat App Using Realm – Integrating Realm into Your App series.
Thanks to their similarities in exposing data through model objects,
converting an app from using Core Data to Realm is very quick and
simple.
In this guide, we've focussed on the code that needs to be changed to
work with Realm, but you'll be pleasantly surprised at just how much
Core Data boilerplate code you're able to simply delete!
If you've been having trouble getting Core Data working in your app, or
you're looking for a way to sync data between platforms, we strongly
recommend giving Realm a try, to see if it works for you. And if it
does, please be sure to let us know!
If you have questions, please head to our developer community
website where the MongoDB engineers and
the MongoDB community will help you build your next big idea with
MongoDB.