Migrating from PouchDB
Description — Couchbase Lite JavaScript — Migrating from PouchDB to Couchbase Lite
Related Content — Databases | Replication
Overview
Couchbase Lite JavaScript provides an officially supported alternative to PouchDB for building offline-first web applications with Sync Gateway.
This guide helps developers migrate from PouchDB to Couchbase Lite JavaScript.
Why Migrate?
Official Couchbase Support: * Full support from Couchbase * Regular updates and security patches * Enterprise-grade reliability
Performance Improvements: * Optimized for modern browser APIs * Better sync reliability with WebSocket protocol * Improved IndexedDB performance
Enhanced Features: * TypeScript support with full type definitions * Advanced conflict resolution strategies * Field-level encryption * Better storage quota management * Production-ready error handling
Better Integration: * Seamless integration with Sync Gateway 3.0+ * Compatible with Couchbase Server 7.0+ * Modern authentication methods * Improved monitoring and logging
API Comparison
Core Operations
| PouchDB API | Couchbase Lite JS API | Notes |
|---|---|---|
|
|
Async operation |
|
|
Properties, not method |
|
|
Collection-based |
|
|
Returns document or null |
|
|
Requires document object |
|
|
Batch operations |
|
|
Iterator pattern |
|
|
Static method |
Query Operations
| PouchDB API | Couchbase Lite JS API | Notes |
|---|---|---|
|
|
SQL++ instead of Mango |
|
Declare in |
At database open time |
|
|
No map/reduce functions |
Replication
| PouchDB API | Couchbase Lite JS API | Notes |
|---|---|---|
|
|
WebSocket-based |
|
|
In ReplicatorConfig |
|
|
In ReplicatorConfig |
|
|
Property, not event |
|
|
Async operation |
Migration Steps
Step 1: Install Couchbase Lite
# Remove PouchDB
npm uninstall pouchdb
# Install Couchbase Lite
npm install @couchbase/lite-js
# Install LogTape for logging (optional)
npm install @logtape/logtape
Step 2: Update Database Initialization
import PouchDB from 'pouchdb';
const db = new PouchDB('myapp');
import { Database } from '@couchbase/lite-js';
const config = {
name: 'myapp',
version: 1,
collections: {
_default: {} // Default collection
}
};
const database = await Database.open(config);
const collection = database.collections._default;
Step 3: Update Document Operations
// Create document
await db.put({
_id: 'doc1',
type: 'task',
title: 'Learn Couchbase',
completed: false
});
// Read document
const doc = await db.get('doc1');
// Update document
doc.completed = true;
await db.put(doc);
// Delete document
await db.remove(doc);
const collection = database.collections._default;
// Create document
await collection.save({
_id: 'doc1',
type: 'task',
title: 'Learn Couchbase',
completed: false
});
// Read document
const doc = await collection.document('doc1');
// Update document
doc.completed = true;
await collection.save(doc);
// Delete document
await collection.deleteDocument(doc);
Step 4: Update Queries
// Create index
await db.createIndex({
index: {
fields: ['type', 'completed']
}
});
// Query documents
const result = await db.find({
selector: {
type: 'task',
completed: false
},
sort: ['title']
});
result.docs.forEach(doc => {
console.log(doc.title);
});
// Declare indexes in config (at database open)
const config = {
name: 'myapp',
version: 1,
collections: {
_default: {
indexes: ['type', 'completed', 'title']
}
}
};
const database = await Database.open(config);
// Query documents with SQL++
const query = database.createQuery(`
SELECT *
FROM _default
WHERE type = 'task' AND completed = false
ORDER BY title
`);
await query.execute(row => {
console.log(row._default.title);
});
Step 5: Update Replication
const sync = PouchDB.sync('myapp', 'http://localhost:4984/myapp', {
live: true,
retry: true
});
sync.on('change', info => {
console.log('Change:', info);
});
sync.on('error', err => {
console.error('Error:', err);
});
import { Replicator } from '@couchbase/lite-js';
const replicator = new Replicator({
database: database,
url: 'wss://localhost:4984/myapp',
collections: {
_default: { pull: {}, push: {} }
},
credentials: {
username: 'user',
password: 'pass'
},
continuous: true
});
replicator.onStatusChange = (status) => {
console.log('Status:', status.activity);
if (status.error) {
console.error('Error:', status.error);
}
};
await replicator.start();
Step 6: Update Change Listeners
const changes = db.changes({
since: 'now',
live: true,
include_docs: true
});
changes.on('change', change => {
console.log('Document changed:', change.id);
});
// Cancel later
changes.cancel();
const collection = database.collections._default;
const token = collection.addChangeListener((changes) => {
changes.documentIDs.forEach(id => {
console.log('Document changed:', id);
});
});
// Remove listener later
collection.removeChangeListener(token);
Data Migration
Export from PouchDB
// Export all documents from PouchDB
const result = await pouchDB.allDocs({
include_docs: true,
attachments: true
});
const docs = result.rows.map(row => row.doc);
// Save to file or prepare for import
const dataExport = {
docs: docs,
timestamp: new Date().toISOString()
};
// Download as JSON
const blob = new Blob(
[JSON.stringify(dataExport, null, 2)],
{ type: 'application/json' }
);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'pouchdb-export.json';
a.click();
Import to Couchbase Lite
import { Database } from '@couchbase/lite-js';
// Open Couchbase Lite database
const database = await Database.open(config);
const collection = database.collections._default;
// Load exported data
const response = await fetch('pouchdb-export.json');
const dataExport = await response.json();
// Import documents in batches
const batchSize = 100;
for (let i = 0; i < dataExport.docs.length; i += batchSize) {
const batch = dataExport.docs.slice(i, i + batchSize);
const docsToSave = batch.map(doc => {
// Remove PouchDB metadata if desired
const { _rev, ...cleanDoc } = doc;
return cleanDoc;
});
await collection.updateMultiple({
save: docsToSave
});
console.log(`Imported ${Math.min(i + batchSize, dataExport.docs.length)} of ${dataExport.docs.length}`);
}
console.log('Migration complete!');
Key Differences
Architecture
PouchDB: * HTTP-based replication (_changes feed, _bulk_docs) * CouchDB replication protocol * Map/reduce for queries
Couchbase Lite: * WebSocket-based replication * Couchbase Mobile protocol * SQL++ for queries * Collection-based data organization
Configuration
PouchDB: * Runtime configuration * Dynamic index creation * Flexible schema
Couchbase Lite: * Indexes declared at database open * Structured configuration * TypeScript schema support
Authentication
PouchDB: * Basic auth in URL or headers * Cookie-based sessions
Couchbase Lite: * Two-step authentication (session + WebSocket) * CORS configuration required * See CORS Configuration
Conflict Resolution
PouchDB: * Automatic conflict resolution * Winner by revision tree depth * Limited custom resolution
Couchbase Lite: * Automatic and custom strategies * Flexible conflict resolvers * See Handling Data Conflicts
Common Pitfalls
1. Sync URL Protocol
Issue: Using HTTP URL instead of WebSocket
url: 'http://localhost:4984/myapp' // Wrong protocol
url: 'ws://localhost:4984/myapp' // For development
url: 'wss://sync.example.com/myapp' // For production (TLS)
2. Index Creation Timing
Issue: Trying to create indexes after database is open
const database = await Database.open(config);
// Cannot create indexes here
const config = {
name: 'myapp',
version: 1,
collections: {
_default: {
indexes: ['field1', 'field2'] // Declare indexes here
}
}
};
const database = await Database.open(config);