docs/replication-appwrite.md
Sync RxDB with Appwrite for local-first apps. Supports real-time updates, offline mode, conflict resolution, and secure push/pull replication.
import {Tabs} from '@site/src/components/tabs'; import {Steps} from '@site/src/components/steps'; import {VideoBox} from '@site/src/components/video-box'; import {RxdbMongoDiagramPlain} from '@site/src/components/mongodb-sync'; import {HeadlineWithIcon} from '@site/src/components/headline-with-icon';
This replication plugin allows you to synchronize documents between RxDB and an Appwrite server. It supports both push and pull replication, live updates via Appwrite's real-time subscriptions, offline-capability and conflict resolution.
<center> <VideoBox videoId="L07xPMyL8sY" title="Appwrite in 100 Seconds" duration="2:35" /> </center>Appwrite is a secure, open-source backend server that simplifies backend tasks like user authentication, storage, database management, and real-time APIs.
RxDatabase is a reactive database for the frontend that offers offline-first capabilities and rich client-side data handling.
Combining the two provides several benefits:
Offline-First: RxDB keeps all data locally, so your application remains fully functional even when the network is unavailable. When connectivity returns, the RxDB ↔ Appwrite replication automatically resolves and synchronizes changes.
Real-Time Sync: With Appwrite’s real-time subscriptions and RxDB’s live replication, you can build collaborative features that update across all clients instantaneously.
Conflict Handling: RxDB offers flexible conflict resolution strategies, making it simpler to handle concurrent edits across multiple users or devices.
Scalable & Secure: Appwrite is built to handle production loads with granular access controls, while RxDB easily scales across various storage backends on the client side.
Simplicity & Modularity: RxDB’s plugin-based architecture, combined with Appwrite’s Cloud offering makes it one of the easiest way to build local-first realtime apps that scale.
You can either use the appwrite cloud or self-host the Appwrite server. In this tutorial we use the Cloud which is recommended for beginners because it is way easier to set up. You can later decide to self-host if needed.
<Steps>Ensure docker and docker-compose is installed and your version are up to date:
docker-compose -v
The installation script runs inside of a docker container. It will create a docker-compose file and an .env file.
docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.6.1
After the installation is done, you can manually stop and start the appwrite instance with docker compose:
# stop
docker-compose down
# start
docker-compose up
Got to the Appwrite Console, create an account and login.
At the console click the + Create Project button to create a new project. Remember the project-id which will be used later.
After creating an Appwrite project you have to create an Appwrite Database and a collection, you can either do this in code with the node-appwrite SDK or in the Appwrite Console as shown in this video:
<center> <VideoBox videoId="HGlBpna17LQ" title="Appwrite Database Tutorial" duration="9:47" startAt={328} /> </center>In the appwrite collection, create all attributes of your documents. You have to define all the fields that your document in your RxDB schema knows about. Notice that Appwrite does not allow for nested attributes. So when you use RxDB with Appwrite, you should also not have nested attributes in your RxDB schema.
deleted attributeAppwrite (natively) hard-deletes documents. But for offline-handling RxDB needs soft-deleted documents on the server so that the deletion state can be replicated with other clients.
In RxDB, _deleted indicates that a document is removed locally and you need a similar field in your Appwrite collection on the Server: You must define a deletedField with any name to mark documents as "deleted" in the remote collection. Mostly you would use a boolean field named deleted (set it to required). The plugin will treat any document with { [deletedField]: true } as deleted and replicate that state to local RxDB.
Appwrite uses permissions to control data access on the collection level. Make sure that in the Console at Collection -> Settings -> Permissions you have set the permission according to what you want to allow your clients to do. For testing, just enable all of them (Create, Read, Update and Delete).
Now that we have set up the Appwrite server, we can go to the client side code and set up RxDB and the replication:
<Steps>npm install appwrite rxdb
import {
replicateAppwrite
} from 'rxdb/plugins/replication-appwrite';
import {
createRxDatabase,
addRxPlugin,
RxCollection
} from 'rxdb/plugins/core';
import {
getRxStorageLocalstorage
} from 'rxdb/plugins/storage-localstorage';
import { Client } from 'appwrite';
const db = await createRxDatabase({
name: 'mydb',
storage: getRxStorageLocalstorage()
});
const mySchema = {
title: 'my schema',
version: 0,
primaryKey: 'id',
type: 'object',
properties: {
id: {
type: 'string',
maxLength: 100
},
name: {
type: 'string'
}
},
required: ['id', 'name']
};
await db.addCollections({
humans: {
schema: mySchema
}
});
const collection = db.humans;
const client = new Client();
client.setEndpoint('https://cloud.appwrite.io/v1');
client.setProject('YOUR_APPWRITE_PROJECT_ID');
const client = new Client();
client.setEndpoint('http://localhost/v1');
client.setProject('YOUR_APPWRITE_PROJECT_ID');
const replicationState = replicateAppwrite({
replicationIdentifier: 'my-appwrite-replication',
client,
databaseId: 'YOUR_APPWRITE_DATABASE_ID',
collectionId: 'YOUR_APPWRITE_COLLECTION_ID',
deletedField: 'deleted', // Field that represents deletion in Appwrite
collection,
pull: {
batchSize: 10,
},
push: {
batchSize: 10
},
/*
* ...
* You can set all other options for RxDB replication states
* like 'live' or 'retryTime'
* ...
*/
});
The RxAppwriteReplicationState which is returned from replicateAppwrite() allows you to run all functionality of the normal RxReplicationState.
Yes, Appwrite supports creating multiple top-level databases within a single project, which cleanly partition collections. However, Appwrite is a rigid NoSQL document store that does not support nested subcollections (unlike Firebase). When utilizing the RxDB Appwrite Replication plugin, your local RxDB schema must mirror this flat topology precisely, keeping all documents completely devoid of complex nested relationships.
</details> <details> <summary>What database driver does Appwrite use under the hood?</summary>Appwrite uses MariaDB (a highly performant MySQL fork) as its core backing database driver. To offer developers a flat NoSQL experience, Appwrite abstracts the MariaDB relational complexity behind a unified Document API. This architectural mapping allows RxDB to replicate data effortlessly into Appwrite via standard REST endpoints without ever dealing with strict SQL table mappings or migrations.
</details> <details> <summary>Does Appwrite feature native real-time sync for offline apps?</summary>Appwrite natively provides robust WebSocket subscriptions allowing clients to receive real-time document events while the network is active. However, Appwrite does not feature a built-in offline-first caching or background-sync engine. To achieve true offline capabilities, you must mount the RxDB Appwrite Replication plugin on the client. RxDB handles all local caching, queues offline writes securely, and automatically pushes local mutations to Appwrite when connectivity returns.
</details>a-z, A-Z, 0-9, and underscore _ (They cannot start with a leading underscore). Also the primary key has a max length of 36 characters.