Build a Mobile App with Sync


After setting up your Android or iOS project to use the MongoDB Stitch SDKs, you are ready to initialize MongoDB Stitch and connect to the database. The following procedure shows you how to build an app that uses MongoDB Mobile and Atlas to store data.

For an example that uses only MongoDB Mobile to store data in an app, see Build a Local-Only Mobile App.

For a complete example app that uses Sync, see the ToDo (Android App) tutorial.


If you have not done so yet, refer to the steps in Set up a MongoDB Mobile Project to set up your Android or iOS project to use the MongoDB Stitch SDKs.


The Stitch SDKs require your Atlas cluster to be version 3.4 or higher. To use Sync, your cluster must be version 3.6 or higher.

Connecting an Android App to Stitch and Atlas

To use the Android SDKs to connect to MongoDB Stitch and sync data between an Atlas cluster to your MongoDB Mobile instance, you can use the following code:

  1. First, you establish a remote connection to Atlas and create a RemoteMongoCollection, as follows:

    // Get a previously defined client or create one
    final StitchAppClient client = Stitch.getDefaultAppClient();
    // Log-in using an Anonymous authentication provider from Stitch
    client.getAuth().loginWithCredential(new AnonymousCredential())
    .addOnCompleteListener(new OnCompleteListener<StitchUser>() {
    public void onComplete(@NonNull Task<StitchUser> task) {
          // Get a remote client
          final RemoteMongoClient remoteMongoClient =
          client.getServiceClient(RemoteMongoClient.factory, "mongodb-atlas");
          // Set up the atlas collection
          RemoteMongoCollection remoteCollection = remoteMongoClient
  2. Next, configure Sync by calling the config() method on the RemoteMongoCollection.sync() interface.

    The Config method takes the following properties:

    • A ConflictHandler, which receives both the remote and local versions of a document when there is a conflict. The Stitch SDKs provides a built-in DefaultSyncConflictResolvers class with two methods, one that uses the local version to resolve the conflict (localWins), and the other that favors the remote version (remoteWins).
    • A ChangeEventListener , which is called whenever a change happens locally or remotely. There is no need to handle the change events yourself, but this provides a hook for you to update your app or perform other change-related logic.
    • An ErrorListener , which receives errors that occur when syncing local changes (for example, if the operation is not permitted by Stitch rules). Your code can check the error, take the appropriate action, and then call resumeSyncForDocument.


    At this point, for all operations on the synced data, be sure to include sync() in your calls, like this: [remoteCollection].sync().[operation].

    // Configure automatic data sync between Atlas and local
    // In this example, conflicts are resolved by giving preference
    // to remote changes.
    new MyUpdateListener(),
    new MyErrorListener());
    private class MyErrorListener implements ErrorListener {
      public void onError(BsonValue documentId, Exception error) {
            Log.e("Stitch", error.getLocalizedMessage());
            Set<BsonValue> docsThatNeedToBeFixed = _remoteCollection.sync().getPausedDocumentIds();
            for (BsonValue doc_id : docsThatNeedToBeFixed) {
                  // Add your logic to inform the user.
                  // When errors have been resolved, call
            // refresh the app view, etc.
    private class MyUpdateListener implements ChangeEventListener<Document> {
      public void onEvent(final BsonValue documentId, final ChangeEvent<Document> event) {
            if (!event.hasUncommittedWrites()) {
                  // Custom actions can go here
            // refresh the app view, etc.
  3. You can now use the RemoteMongoCollection.sync() interface to perform CRUD operations. For example, you can insert a document into the local database (which will automatically sync with the remote database), and perform custom logic when the insert is complete:

    final Task<RemoteInsertOneResult> res = _remoteCollection.sync().insertOne(doc);
    res.addOnCompleteListener(new OnCompleteListener<RemoteInsertOneResult>() {
       public void onComplete(@NonNull final Task<RemoteInsertOneResult> task) {
             if (task.isSuccessful()) {
                // do something
             } else {
                Log.e(TAG, "Error adding item", task.getException());