Configure & Open a Synced Realm - Node.js SDK
On this page
Synced Realms
You can configure a realm to automatically synchronize data between many devices that each have their own local copy of the data. Synced realms use a different configuration than local-only realms and require an Atlas App Services backend to handle the synchronization process.
Applications can always create, modify, and delete synced realm objects locally, even when offline. Whenever a network connection is available, the Realm SDK opens a connection to an application server and syncs changes to and from other clients. The Atlas Device Sync protocol and server-side operational transforms guarantee that all fully synced instances of a realm see exactly the same data, even if some changes occurred offline and/or were received out of order.
Tip
Learn How to Configure and Use Sync
For more information on synced realms, including directions on how to set up sync in a Realm app, see Atlas Device Sync Overview.
Prerequisites
Before you configure a realm with Flexible Sync in a Node.js application:
Enable Flexible Sync on the backend. You must configure Flexible Sync in the backend before you can use it with your client application.
Authenticate a user in your client project.
Open a Synced Realm
The first step in implementing Device Sync is to open the synced Realm. The following information pertains to an app using Flexible Sync. If your existing app uses the older Partition-Based Sync, refer to Open a Partition-Based Synced Realm. If you have not yet decided or are unsure which to use, read the Choose Your Sync Mode page.
To open a realm using Flexible Sync, call Realm.open().
Pass in a ConfigurationWithSync
object, which must include the sync
property defining a
SyncConfiguration object.
In the SyncConfiguration, you must include include a user
and flexible:true
.
const realm = await Realm.open({ schema: [TaskSchema, TeamSchema], sync: { user: app.currentUser, flexible: true, }, });
By default, Realm syncs all data from the server before returning. If you want to sync data in the background, read the Open a Synced Realm While Offline section.
Important
Flexible Sync Requires a Subscription
You can't use a Flexible Sync realm until you add at least one subscription. To learn how to add subscriptions, see: Add a Subscription.
Open Synced Realm at Specific Path
New in version realm@11.6.0
.
Using AppConfiguration.baseFilePath, and Realm.Configuration.path, you can control where Realm and metadata files are stored on client devices.
To do so, set <AppProvider>.baseFilePath
. If baseFilePath
is not set, the
current work directory is used. You can also set <RealmProvider>.sync.path
for more control.
const app = new Realm.App({ id: APP_ID, baseFilePath: customPath }); const user = await app.logIn(Realm.Credentials.anonymous()); const realm = await Realm.open({ schema: [Car], sync: { flexible: true, user, }, });
If baseFilePath
is set, metadata is always stored in
<baseFilePath>/mongodb-realm/
. If baseFilePath
isn't set, then metadata
is stored in <Realm.defaultPath>/mongodb-realm
.
Where exactly your Realm file is stored can vary depending on how you set Realm.Configuration.path:
Realm.Configuration.path
is not set andbaseFilePath
is set. Your Realm file is stored atbaseFilePath
.Realm.Configuation.path
is set to a relative path. Your Realm file is stored relative tobaseFilePath
.Realm.Configuration.path
is an absolute path. Your Realm file is stored atRealm.Configuration.path
.
Open a Synced Realm While Offline
When your Realm application authenticates a user, it caches the user's credentials. You can check for existing user credentials to bypass the login flow and access the cached user. Use this to open a realm offline.
Note
Initial login requires a network connection
When a user signs up for your app, or logs in for the first time with an existing account on a client, the client must have a network connection. Checking for cached user credentials lets you open a realm offline, but only if the user has previously logged in while online.
// Log user into your App Services App. // On first login, the user must have a network connection. const getUser = async () => { // If the device has no cached user credentials, log in. if (!app.currentUser) { const credentials = Realm.Credentials.anonymous(); await app.logIn(credentials); } // If the app is offline, but credentials are // cached, return existing user. return app.currentUser!; };
The following subsections show how to use background synchronization to access a realm while offline. To do this, use the cached user and an OpenRealmBehaviorConfiguration object.
Within your Sync Configuration, set the optional newRealmFileBehavior
and
existingRealmFileBehavior
fields to your OpenRealmBehaviorConfiguration
object
to enable background synchronization.
Important
Offline Login is Supported for Both Flexible and Partition-Based Sync Configurations
You can open a realm immediately with background sync or after a timeout elapses using Flexible Sync or the older Partition-Based Sync.
Partition-Based Sync is an outdated sync mode. See the Partition-Based Sync - Node.js SDK page for details on using Partition-Based Sync for your application.
Open Immediately with Background Sync
If the user's device is not connected to the internet or you're uncertain of
it's connection status, set the realm behavior's type to openImmediately
. This
syncs data from the server in the background.
const behaviorConfiguration = { type: "openImmediately", }; const config = { schema: [Car], sync: { user: await getUser(), flexible: true, newRealmFileBehavior: behaviorConfiguration, existingRealmFileBehavior: behaviorConfiguration, }, }; const realm = await Realm.open(config);
const behaviorConfiguration: Realm.OpenRealmBehaviorConfiguration = { type: "openImmediately", }; const config: Realm.Configuration = { schema: [Car], sync: { user: await getUser(), flexible: true, newRealmFileBehavior: behaviorConfiguration, existingRealmFileBehavior: behaviorConfiguration, }, }; const realm = await Realm.open(config);
Open After Timeout with Background Sync
If you want to sync data but you're in an environment where it's uncertain if
the user has an Internet connection, specify a timeOut
. This
automatically opens the realm when either:
the timeout period elapses.
the realm has completely downloaded.
If the realm doesn't finish downloading before the timeout, the initial realm sync continues in the background.
const behaviorConfiguration = { type: "openImmediately", timeOut: 1000, timeOutBehavior: "openLocalRealm", }; const config = { schema: [Car], sync: { flexible: true, user: await getUser(), existingRealmFileBehavior: behaviorConfiguration, newRealmFileBehavior: behaviorConfiguration, }, }; const realm = await Realm.open(config);
const behaviorConfiguration: Realm.OpenRealmBehaviorConfiguration = { type: "openImmediately", timeOut: 1000, timeOutBehavior: "openLocalRealm", }; const config: Realm.Configuration = { schema: [Car], sync: { flexible: true, user: await getUser(), existingRealmFileBehavior: behaviorConfiguration, newRealmFileBehavior: behaviorConfiguration, }, }; const realm = await Realm.open(config);
Sync Changes in the Background
You may want to sync changes in the background to display partial data to the user while the synced realm downloads data from the server, preventing the user experience from being blocked. We recommend syncing changes in the background for applications in which the user's device may go offline. To sync changes in the background, open a synced realm synchronously.
Create a OpenRealmBehaviorConfiguration object and set its
type
to "openImmediately"
.
const behaviorConfiguration = { type: "openImmediately", };
const behaviorConfiguration: Realm.OpenRealmBehaviorConfiguration = { type: Realm.OpenRealmBehaviorType.OpenImmediately, };
Create a Configuration object, which must
include the sync
property defining a SyncConfiguration object. Set this
OpenRealmBehaviorConfiguration
object as the value for
the newRealmFileBehavior
and existingRealmFileBehavior
fields of the
SyncConfiguration
.
const config = { schema: [DogSchema], sync: { user: app.currentUser, partitionValue: "MyPartitionValue", // The behavior to use when this is the first time opening a realm. newRealmFileBehavior: behaviorConfiguration, // The behavior to use when a realm file already exists locally, // i.e. you have previously opened the realm. existingRealmFileBehavior: behaviorConfiguration, }, };
const config: Realm.Configuration = { schema: [DogSchema], sync: { user: app.currentUser!, partitionValue: "MyPartitionValue", // The behavior to use when this is the first time opening a realm. newRealmFileBehavior: behaviorConfiguration, // The behavior to use when a realm file already exists locally, // i.e. you have previously opened the realm. existingRealmFileBehavior: behaviorConfiguration, }, };
Finally, call Realm.open() to open a synced realm. This will create a sync session and begin downloading any existing data from the server in the background.
const realm = await Realm.open(config);
Cancel Asynchronous Operations after a Timeout
New in version 12.0.0.
You can specify a cancelWaitsOnNonFatalErrors
property in your
BaseSyncConfiguration object.
When true
, the Node.js SDK cancels asynchronous operations, such as
waiting for uploads or downloads, when a timeout period elapses. You can
define the timeout for this option on the
AppConfiguration.
For an example, refer to Configure a Timeout for the App Client.
This property defaults to false
if you do not specify a value.
const config = { schema: [Doggie], sync: { flexible: true, user: app.currentUser, // When `true`, upload and download waits are canceled on any // error, such as a timeout, instead of just a fatal error. // You can provide an optional timeouts property in milliseconds. cancelWaitsOnNonFatalError: true, }, };
const config: Realm.Configuration = { schema: [Doggie], sync: { flexible: true, user: app.currentUser!, // When `true`, upload and download waits are canceled on any // error, such as a timeout, instead of just a fatal error. // You can provide an optional timeouts property in milliseconds. cancelWaitsOnNonFatalError: true, }, };