Implementing Realm Sync in an Android App: From Setup to Troubleshooting
Learn how to add real‑time sync to your Android app with MongoDB Realm. This guide covers prerequisites, configuration, verification, and common pitfalls, ensuring your data stays consistent across devices.
05 Sept 2025, 13:50 UTC

Desired Outcome
By the end of this guide you will have a working Android application that uses Realm Sync to keep data consistent across multiple devices in real time. The app will:
- Authenticate users via email/password.
- Open a synced Realm instance tied to the user’s session.
- Automatically propagate CRUD operations to the MongoDB Atlas backend and all other connected clients.
- Expose sync status and error callbacks for reliable debugging.
Prerequisites
- Android Studio 2022.1.1 or newer.
- Java 11 or Kotlin (this guide uses Kotlin).
- MongoDB Atlas account with a paid Realm plan (free tiers do not support sync).
- Realm app created in the Atlas console with a matching schema.
- Network connectivity; sync requires HTTPS.
Client‑Side Dependencies
Add the Realm SDK to your app module’s build.gradle.kts (or build.gradle if using Groovy):
plugins {
id("com.android.application")
id("kotlin-android")
}
android {
compileSdk = 34
defaultConfig {
applicationId = "com.example.realmapp"
minSdk = 21
targetSdk = 34
versionCode = 1
versionName = "1.0"
}
buildFeatures { viewBinding = true }
}
dependencies {
implementation("io.realm:realm-android-sync:10.14.0")
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")
}
Replace the version numbers with the latest stable releases at the time of your build. Sync is only available in the realm-android-sync artifact.
Configure the Realm App in Atlas
- Log into the MongoDB Atlas console.
- Create a new Realm app or select an existing one.
- Navigate to Data Access > Schemas and define your object schema. For example:
{
"name": "Task",
"properties": {
"_id": {"type": "objectId", "default": "new ObjectId()"},
"title": "string",
"completed": "bool"
}
}
Ensure the server schema matches the local model exactly, including field types and primary keys. Mismatches trigger sync failures.
Authentication
Enable Email/Password in the Realm app’s Authentication tab. No API keys are needed for per‑user sync sessions.
Local Model Definition
Define the same schema in your Android code. With Kotlin, use RealmObject and PrimaryKey annotations:
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.types.ObjectId
open class Task(
@PrimaryKey
var _id: ObjectId = ObjectId(),
var title: String = "",
var completed: Boolean = false
) : RealmObject()
Compile‑time checks in Realm Kotlin ensure the model matches the server schema.
Initialize Sync in the Application Class
Set up the sync configuration once, typically in a custom Application subclass:
import android.app.Application
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmLog
import io.realm.log.LogLevel
import io.realm.kotlin.Realm.getInstance
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// Optional: enable debug logging to trace sync events
RealmLog.setLogLevel(LogLevel.DEBUG)
// Build the sync configuration
val config = RealmConfiguration.Builder(schema = setOf(Task::class))
.syncConfiguration(
io.realm.SyncConfiguration.Builder("user@example.com", "password123")
.build()
)
.name("tasks.realm")
.build()
// Initialize the default realm instance
Realm.setDefaultConfiguration(config)
}
}
Replace user@example.com and password123 with the credentials of a registered user. In production, obtain credentials via a login flow and store them securely (e.g., Android Keystore).
Opening a Synced Realm Instance
import io.realm.kotlin.Realm
import io.realm.kotlin.where
// Inside an Activity or ViewModel
val realm = Realm.getDefaultInstance()
realm.write {
copyToRealm(Task(title = "First Task"))
}
// Querying
val tasks = realm.query().find()
All writes performed within realm.write blocks are automatically queued for sync. No manual push is required.
Monitoring Sync State
Use SyncSession callbacks to detect connectivity, errors, and completion:
import io.realm.sync.SyncSession
import io.realm.sync.SyncSessionStatus
val syncSession: SyncSession = realm.syncSession()
syncSession.addChangeListener { status: SyncSessionStatus ->
when (status) {
SyncSessionStatus.CONNECTED -> Log.i("Sync", "Connected to server")
SyncSessionStatus.DISCONNECTED -> Log.w("Sync", "Disconnected")
SyncSessionStatus.ERROR -> Log.e("Sync", "Error: ${status.error?.message}")
else -> {}
}
}
Check the status at any point:
val currentStatus = syncSession.status
println("Sync status: $currentStatus")
Verification Steps
- Launch the app on two Android devices (or emulators) using the same email/password credentials.
- On device A, create a new
Taskobject. Observe the UI update on device B within seconds. - In the app, call
realm.syncSession().statusand confirm it reportsCONNECTEDwith no errors. - Log into the Atlas console, navigate to the Realm app’s Data tab, and verify the new Task appears in the collection.
- Enable
RealmLog.setLogLevel(LogLevel.DEBUG)and watch the logcat for sync events likeSyncSession: ConnectedorSyncSession: Syncing.
Troubleshooting Common Issues
1. Schema Mismatch
When the server schema differs from the client model, sync will fail with a SyncSchemaMismatchError. Verify both schemas match exactly. If a change is needed, update the server schema and run a client migration:
RealmConfiguration.Builder(schema = setOf(Task::class))
.migration { realm, oldVersion, newVersion ->
// No-op if only adding fields; otherwise handle data transformation
}
.build()
2. Network Interruptions
Sync is resilient to temporary network loss. The session will pause and resume automatically. Monitor SyncSessionStatus.DISCONNECTED and CONNECTED callbacks to inform users of connectivity changes.
3. Authentication Failures
Wrong credentials or disabled authentication methods will prevent session creation. Ensure the Realm app has Email/Password enabled and that the user exists. Use the RealmApp.loginWithCredential API to catch and handle login errors before opening a Realm.
4. Paid Plan Requirement
Sync is only available on paid Realm plans. Verify your Atlas subscription supports sync. If you’re on a free tier, the sync client will throw SyncNotEnabledError upon session creation.
Rollback Considerations
Changing the Realm schema or sync configuration alters the persisted data. If you need to revert a schema change, use Realm’s migration system or delete the local realm file (realm.close(); realm.deleteRealm()) and let the sync process rebuild the database. Always back up data before performing destructive operations.
Conclusion
Realm Sync simplifies real‑time data replication across Android devices. By keeping client and server schemas in sync, handling authentication securely, and monitoring session status, you can deliver a seamless user experience. Use the steps above to set up, verify, and troubleshoot your sync implementation.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.