PouchDB Syncing Reference
This page provides a complete reference for PouchDB synchronization options and advanced configuration. For a practical walkthrough with examples, see the Syncing Overview.
Overview
The PouchDB plugin integrates with PouchDB’s replication engine, which provides battle-tested sync capabilities for CouchDB-compatible databases. When you configure the sync option, the plugin automatically sets up bidirectional replication between your local and remote databases.
Sync Configuration Options
remoteDb (Required)
The URL to your remote CouchDB-compatible database. Must be a valid HTTP/HTTPS URL.
import { PouchDbPlugin } from "@routier/pouchdb-plugin";
const plugin = new PouchDbPlugin("myapp", {
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
},
});
live (Optional)
Enable continuous synchronization. When true, the sync will continue running and pick up changes in real-time. When false, sync happens once on startup.
Default: false
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
live: true // Continuous sync
}
retry (Optional)
Enable automatic retry with exponential backoff. When enabled, failed sync operations automatically retry with increasing delays (1s, 2s, 4s, up to 10s max).
Default: false
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
retry: true // Auto-retry failed syncs
}
pull (Optional)
Configure options for pulling changes from remote. This is an object that can include:
live: Continuous pull (default: false)retry: Auto-retry failed pulls (default: false)filter: Function to filter documents during pull- Any other PouchDB replication options
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
pull: {
live: true,
retry: true,
filter: (doc) => doc.collectionName === "public_data"
}
}
push (Optional)
Configure options for pushing changes to remote. Can be set to false to disable pushing, or an object with push-specific options.
- Set to
false: Disable pushing (pull-only sync) - Object: Configuration for pushing (similar structure to
pull)
// Pull-only sync
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
pull: { live: true },
push: false
}
// Configure push options
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
push: {
live: true,
retry: true
}
}
filter (Optional)
Function to filter documents during sync. The filter function receives a document and returns true to include it or false to exclude it.
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
filter: (doc) => {
// Only sync documents from specific collections
return doc.collectionName === "item" || doc.collectionName === "category";
}
}
Note: Filters apply to both pull and push unless specified separately in pull or push options.
onChange (Optional)
Callback function that receives sync events. Use this to process synced documents manually, track progress, or handle conflicts.
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onChange: (schemas, change) => {
if (change.direction === "pull" && change.change?.docs) {
// Process pulled documents
console.log(`Pulled ${change.change.docs.length} documents`);
}
}
}
Parameters:
schemas:SchemaCollection- Collection of all schemas in the datastorechange:PouchDB.Replication.SyncResult<{}>- The sync event from PouchDB
See: Processing Sync Events for detailed examples.
onError (Optional)
Callback function called when a sync error occurs.
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onError: (schemas, error) => {
console.error("Sync error:", error);
// Handle error, notify user, etc.
}
}
onComplete (Optional)
Callback function called when a sync operation completes (only for non-live syncs).
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onComplete: (schemas, event) => {
console.log("Sync completed:", event);
}
}
onPaused (Optional)
Callback function called when sync is paused (typically due to network issues).
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onPaused: (schemas, event) => {
console.log("Sync paused - network may be unavailable");
}
}
onActive (Optional)
Callback function called when sync becomes active after being paused.
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onActive: (schemas) => {
console.log("Sync resumed");
}
}
onDenied (Optional)
Callback function called when sync is denied (typically due to authentication/permission issues).
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onDenied: (schemas, event) => {
console.error("Sync denied:", event);
}
}
auth (Optional)
Authentication credentials for the remote database.
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
auth: {
username: "myuser",
password: "mypassword"
}
}
headers (Optional)
Custom HTTP headers to send with sync requests.
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
headers: {
"X-Custom-Header": "value"
}
}
Processing Sync Events
The onChange callback receives sync events that contain information about what documents were changed. Use this to:
- Group documents by collection
- Route documents to the appropriate schema
- Apply custom transformations
- Track sync progress
Basic Usage
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onChange: (schemas, change) => {
if (change.direction === "pull" && change.change?.docs) {
console.log(`Pulled ${change.change.docs.length} documents`);
} else if (change.direction === "push" && change.change?.docs) {
console.log(`Pushed ${change.change.docs.length} documents`);
}
}
}
Routing Documents by Collection
Process documents by grouping them by collection name:
import { DataStore } from "@routier/datastore";
import { PouchDbPlugin } from "@routier/pouchdb-plugin";
import { s } from "@routier/core/schema";
import { UnknownRecord } from "@routier/core";
import { SchemaCollection } from "@routier/core/collections";
// Define schemas
const itemSchema = s
.define("item", {
id: s.string().key().identity(),
name: s.string(),
description: s.string(),
createdAt: s.date(),
})
.compile();
const categorySchema = s
.define("category", {
id: s.string().key().identity(),
name: s.string(),
description: s.string(),
})
.compile();
// Configure PouchDB with pull-only sync and filtering
const plugin = new PouchDbPlugin("myapp", {
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
pull: {
live: true,
retry: true,
// Optional
filter: (doc) => {
// Only sync documents from specific collections
return doc.collectionName === "item" || doc.collectionName === "category";
},
},
push: false as any, // Pull-only sync
onChange: (schemas: SchemaCollection, change: any) => {
if (change.direction !== "pull" || !change.change.docs) return;
// Group documents by collection
const docsByCollection = change.change.docs.reduce(
(acc: { [key: string]: UnknownRecord[] }, doc: UnknownRecord) => {
const name = doc.collectionName as string;
if (name) (acc[name] ??= []).push(doc);
return acc;
},
{} as { [key: string]: UnknownRecord[] }
);
// Process each collection
for (const [name, docs] of Object.entries(docsByCollection)) {
const schema = schemas.getByName(name);
if (!schema) continue;
const subscription = schema.createSubscription();
subscription.send({ adds: [], removals: [], updates: [], unknown: docs });
subscription[Symbol.dispose]();
}
},
},
});
// Create DataStore with plugin
class AppDataStore extends DataStore {
items = this.collection(itemSchema).create();
categories = this.collection(categorySchema).create();
constructor() {
super(plugin);
}
}
const ctx = new AppDataStore();
// Sync starts automatically when plugin is created
// Remote changes will be pulled automatically based on the filterConflict Resolution
PouchDB automatically detects conflicts when the same document is modified in both local and remote databases. Conflicts are indicated by the _conflicts property on documents.
Detecting Conflicts
Check for conflicts in your onChange callback:
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
onChange: (schemas, change) => {
if (change.change?.docs) {
change.change.docs.forEach((doc) => {
if (doc._conflicts && doc._conflicts.length > 0) {
console.warn(`Conflict detected in document ${doc._id}`);
// Handle conflict: merge, use local, use remote, etc.
}
});
}
}
}
Resolving Conflicts
You can resolve conflicts by:
- Using the local version: Delete the remote conflict revisions
- Using the remote version: Delete the local version
- Merging: Combine changes from both versions
- Using business logic: Apply domain-specific rules to determine the winner
Advanced PouchDB Options
The PouchDB plugin accepts all standard PouchDB replication options. These are passed through to PouchDB’s sync() method. Refer to PouchDB’s replication documentation for the complete list.
Common advanced options include:
doc_ids: Array of document IDs to syncquery_params: Additional query parameters for filtered replicationview: Use a CouchDB view for filteringsince: Sync only changes since a specific sequence numberheartbeat: Interval for heartbeat requests in millisecondstimeout: Timeout for requests in millisecondsbatch_size: Number of documents to process per batchbatches_limit: Maximum number of batches to process per replication cycle
Sync Patterns
Pull-Only Sync
Use pull-only sync when you want to receive updates from a server but don’t want local changes to sync back:
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
pull: {
live: true,
retry: true
},
push: false
}
Push-Only Sync
Use push-only sync to send local changes to a server without receiving updates:
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
pull: false,
push: {
live: true,
retry: true
}
}
Bidirectional Sync
Default behavior when both directions are enabled:
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
live: true,
retry: true
}
One-Time Sync
Perform a single sync operation without live updates:
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
live: false
}
Starting Sync
After creating the plugin, you need to start the sync process. The plugin provides a sync() method that you should call:
import { DataStore } from "@routier/datastore";
import { PouchDbPlugin } from "@routier/pouchdb-plugin";
const plugin = new PouchDbPlugin("myapp", {
sync: {
remoteDb: "http://127.0.0.1:5984/myapp",
live: true,
retry: true,
},
});
class AppDataStore extends DataStore {
constructor() {
super(plugin);
}
}
const store = new AppDataStore();
// Start sync
plugin.sync(store.schemas);
Troubleshooting
Sync Not Starting
- Verify
remoteDbURL is correct and accessible - Check that sync options are provided in the plugin constructor
- Ensure
plugin.sync(store.schemas)is called after datastore creation
Authentication Errors
- Verify credentials in
authoption - Check that the user has read/write permissions on the remote database
- Test the remote database URL in a browser or with curl
Network Issues
- Verify network connectivity
- Check CORS settings on the remote server
- Review firewall/proxy settings
- Use
onPausedandonActivecallbacks to monitor connection state
Conflicts
- Implement conflict resolution in your
onChangecallback - Use document versioning strategies
- Consider business logic for merging conflicting changes
Performance Issues
- Use
filterto reduce the number of documents synced - Adjust
batch_sizeif syncing large datasets - Monitor sync progress with
onChangecallbacks - Consider using views for more efficient filtering
Next Steps
- Syncing Overview - Practical example and walkthrough
- Syncing Guide - Conceptual overview of syncing in Routier
- PouchDB Plugin - PouchDB plugin documentation
- Live Queries - Real-time data queries
- Change Tracking - Understanding how Routier tracks changes