Skip to content
Apache CouchDB Guide — Document-Oriented NoSQL Database

Apache CouchDB Guide — Document-Oriented NoSQL Database

DodaTech Updated Jun 7, 2026 10 min read

Apache CouchDB is a document-oriented NoSQL database that stores JSON documents, exposes a RESTful HTTP API, and provides multi-master replication, conflict resolution, and a built-in MapReduce view engine.

What You’ll Learn

By the end of this tutorial, you’ll understand CouchDB’s document model, interact with the database using the REST API, create MapReduce views for querying, set up replication between instances, resolve conflicts, and synchronize with PouchDB for offline-first web applications.

Why CouchDB Matters

CouchDB is uniquely designed for offline-first and multi-device sync scenarios. It powers applications that need to work without internet — like mobile field service apps, point-of-sale systems in remote areas, and collaborative tools. Doda Browser uses CouchDB for its cross-device bookmark sync, while Durga Antivirus Pro leverages CouchDB’s replication for distributing threat definitions to offline endpoints. Learning CouchDB gives you a skill essential for modern offline-capable applications.

CouchDB Learning Path

    flowchart LR
  A[SQL Basics] --> B[MongoDB]
  B --> C[CouchDB]
  C --> D[Elasticsearch]
  D --> E[Redis]
  E --> F[Database Design]
  C --> G{You Are Here}
  style G fill:#f90,color:#fff
  
Prerequisites: Understanding of REST API concepts (HTTP methods, JSON). JavaScript knowledge is helpful for writing MapReduce views. No prior NoSQL experience is required.

What Is CouchDB? (The “Why” First)

Think of CouchDB as a database that speaks HTTP. Unlike SQL databases that use custom wire protocols, every CouchDB operation is an HTTP request. Your data is JSON, your queries are HTTP GET requests, your updates are HTTP PUT/POST requests. This makes CouchDB incredibly easy to use from any web or mobile application — no special drivers needed. But CouchDB’s superpower is replication: you can have CouchDB instances on phones, laptops, and servers, all syncing data automatically, even with intermittent connectivity.

CouchDB vs MongoDB

FeatureCouchDBMongoDB
StorageAppend-only (no overwrite)In-place updates
QueryMapReduce viewsAggregation pipeline, indexes
APIRESTful HTTPCustom wire protocol (BSON)
ReplicationMulti-master (built-in)Replica sets (master-slave)
Conflict handlingAutomatic (multi-victor)Last-write-wins
ACIDPer-documentMulti-document
Best forOffline-first, sync appsGeneral-purpose, analytics

Documents — The Core of CouchDB

Everything in CouchDB is a JSON document. Each document has a unique _id and a revision _rev (used for conflict detection):

{
  "_id": "user_alice",
  "_rev": "1-abc123def456",
  "type": "user",
  "name": "Alice Johnson",
  "email": "alice@example.com",
  "age": 28,
  "addresses": [
    {"city": "New York", "zip": "10001", "type": "home"},
    {"city": "Boston", "zip": "02101", "type": "work"}
  ],
  "created_at": "2026-06-07T10:00:00Z"
}

Working with the REST API

All CouchDB interactions use HTTP methods:

# Create a database
curl -X PUT http://admin:password@localhost:5984/shop

# Response: {"ok":true}

# Create a document
curl -X POST http://admin:password@localhost:5984/shop \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "product_laptop",
    "type": "product",
    "name": "MacBook Pro",
    "price": 2499,
    "category": "Electronics",
    "in_stock": true,
    "tags": ["apple", "laptop", "pro"]
  }'

# Response: {"ok":true, "id":"product_laptop", "rev":"1-abc123"}

# Create another document
curl -X POST http://admin:password@localhost:5984/shop \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "product_mouse",
    "type": "product",
    "name": "Magic Mouse",
    "price": 79,
    "category": "Electronics",
    "in_stock": true,
    "tags": ["apple", "mouse", "wireless"]
  }'

Reading Documents

# Get a document by ID
curl http://admin:password@localhost:5984/shop/product_laptop

# Response:
{
  "_id": "product_laptop",
  "_rev": "1-abc123",
  "type": "product",
  "name": "MacBook Pro",
  "price": 2499,
  "category": "Electronics",
  "in_stock": true,
  "tags": ["apple", "laptop", "pro"]
}

# Update a document (include _rev!)
curl -X PUT http://admin:password@localhost:5984/shop/product_laptop \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "product_laptop",
    "_rev": "1-abc123",
    "name": "MacBook Pro 2026",
    "price": 2599,
    "category": "Electronics",
    "in_stock": true,
    "tags": ["apple", "laptop", "pro"]
  }'

# Response: {"ok":true, "id":"product_laptop", "rev":"2-def456"}

MapReduce Views — Querying Data

Unlike MongoDB’s aggregation pipeline, CouchDB uses MapReduce views — pre-computed indexes defined as JavaScript functions:

// View: Products by category
// Saved as _design/products/_views/by_category

// Map function
function(doc) {
  if (doc.type === 'product' && doc.category) {
    emit(doc.category, {
      name: doc.name,
      price: doc.price,
      in_stock: doc.in_stock
    });
  }
}

// Reduce function (optional) — count per category
function(keys, values, rereduce) {
  return values.length;
}

Query the view:

# Get all products grouped by category
curl http://admin:password@localhost:5984/shop/_design/products/_view/by_category?group=true

# Response:
{
  "rows": [
    {"key": "Electronics", "value": 2}
  ]
}

# Get products in Electronics category
curl http://admin:password@localhost:5984/shop/_design/products/_view/by_category?key="Electronics"

# Response:
{
  "rows": [
    {"key": "Electronics", "value": {"name": "MacBook Pro", "price": 2499, "in_stock": true}},
    {"key": "Electronics", "value": {"name": "Magic Mouse", "price": 79, "in_stock": true}}
  ]
}

More Complex View — Products by Price Range

// Map function
function(doc) {
  if (doc.type === 'product' && doc.price) {
    var range;
    if (doc.price < 100) range = 'budget';
    else if (doc.price < 500) range = 'mid';
    else range = 'premium';
    emit([range, doc.price], doc.name);
  }
}
# Query premium products
curl 'http://admin:password@localhost:5984/shop/_design/products/_view/by_price_range?startkey=["premium",0]&endkey=["premium",999999]'

# Response:
{
  "rows": [
    {"key": ["premium", 2499], "value": "MacBook Pro"}
  ]
}

Replication

CouchDB’s replication is its killer feature — it syncs databases between any two endpoints:

# Trigger replication from a remote database to local
curl -X POST http://admin:password@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "http://admin:password@remote-server:5984/shop",
    "target": "shop_local",
    "continuous": true
  }'

# One-shot replication
curl -X POST http://admin:password@localhost:5984/_replicate \
  -H "Content-Type: application/json" \
  -d '{
    "source": "shop",
    "target": "http://admin:password@backup-server:5984/shop_backup"
  }'

CouchDB Replication Architecture

    flowchart TB
    subgraph Server
        C1[CouchDB Main]
        S1[_replicator Database]
    end
    subgraph Mobile Devices
        P1[PouchDB - Phone]
        P2[PouchDB - Tablet]
        P3[PouchDB - Laptop]
    end
    subgraph Backup
        C2[CouchDB Backup]
    end
    C1 <-->|Continuous Replication| P1
    C1 <-->|Continuous Replication| P2
    C1 <-->|Continuous Replication| P3
    C1 -->|One-shot Replication| C2
    P1 <-->|Peer-to-Peer| P2
  

Every CouchDB (and PouchDB) instance can replicate with every other instance. Changes flow in both directions — multi-master replication built in.

Conflict Resolution

When the same document is edited on two offline devices, CouchDB creates conflicting revisions:

# Check for conflicts
curl http://admin:password@localhost:5984/shop/product_laptop?conflicts=true

# Response shows conflicting revisions:
{
  "_id": "product_laptop",
  "_rev": "3-ghi789",
  "name": "MacBook Pro",
  ...
  "_conflicts": ["2-def456"]
}

# Get the conflicting revision
curl http://admin:password@localhost:5984/shop/product_laptop?rev=2-def456

# Resolve by merging and deleting the conflict
curl -X PUT http://admin:password@localhost:5984/shop/product_laptop \
  -H "Content-Type: application/json" \
  -d '{
    "_id": "product_laptop",
    "_rev": "3-ghi789",
    "name": "MacBook Pro (merged)",
    ...
  }'

# Delete the conflict revision
curl -X DELETE http://admin:password@localhost:5984/shop/product_laptop?rev=2-def456

PouchDB — CouchDB for the Browser

PouchDB is a JavaScript implementation of CouchDB that runs in the browser:

// Create a local database
const db = new PouchDB('shop_offline');

// Save a document
db.put({
  _id: 'product_tablet',
  type: 'product',
  name: 'iPad Pro',
  price: 1099,
  category: 'Electronics'
}).then(response => {
  console.log('Saved:', response.id);
}).catch(err => {
  console.error('Error:', err);
});

// Query local data
db.allDocs({include_docs: true}).then(result => {
  result.rows.forEach(row => {
    console.log(row.doc.name, '-', row.doc.price);
  });
});

// Sync with remote CouchDB
const remote = new PouchDB('http://admin:password@localhost:5984/shop');

db.sync(remote, {
  live: true,
  retry: true
}).on('change', change => {
  console.log('Changes synced:', change);
}).on('error', err => {
  console.error('Sync error:', err);
});

Common CouchDB Errors

1. {"error":"not_found","reason":"missing"}

The requested document doesn’t exist. Fix: Check the _id spelling. Use GET /database/_all_docs to list all document IDs.

2. {"error":"conflict","reason":"Document update conflict."}

You tried to update a document without providing the latest _rev. Fix: Always read the document first to get its current _rev, then include it in your PUT request.

3. {"error":"unauthorized","reason":"You are not authorized to access this db."}

Authentication required. Fix: Include credentials in the URL: http://user:pass@localhost:5984/db. Configure admin credentials in local.ini.

4. {"error":"file_error","reason":"Could not open database file"}

CouchDB cannot access its data directory. Fix: Check disk space, permissions, and the database_dir setting in local.ini.

5. View Build Failure

If your MapReduce view contains JavaScript errors, CouchDB reports the error when you query. Fix: Test your view functions in a JavaScript console before saving. Check _design/docs/_view/name?stale=ok for partially built views.

6. {"error":"bad_request","reason":"Referer header required for design document access."}

CORS settings restrict requests. Fix: Configure CORS in local.ini:

[cors]
origins = *
methods = GET, PUT, POST, DELETE, OPTIONS

7. Replication Hangs

Large databases or frequent conflicts can stall replication. Fix: Check _active_tasks for replication status. Cancel and restart the replication. Ensure both ends have enough disk space.

Practice Questions

1. What is a document revision (_rev) in CouchDB?

Each edit to a document creates a new revision. The _rev is used for conflict detection — you must provide the latest _rev to update or delete a document. If someone else updated the document since you read it, your write will conflict.

2. How does CouchDB replication work?

CouchDB uses multi-master replication — any database can push changes to any other database. Replication can be one-shot (single sync) or continuous (live). Changes are tracked using a sequence number per database.

3. What is a MapReduce view?

A MapReduce view is a pre-computed index defined by JavaScript functions. The map function emits key-value pairs from documents. The optional reduce function aggregates results (like COUNT, SUM). Views are updated incrementally as documents change.

4. Challenge: Write a MapReduce view that finds all products with prices between 50 and 200.

// Map function
function(doc) {
  if (doc.type === 'product' && doc.price >= 50 && doc.price <= 200) {
    emit(doc.price, doc.name);
  }
}

Query with: GET /db/_design/products/_view/by_price_range

5. How does CouchDB handle conflicts differently from MongoDB?

CouchDB preserves all conflicting revisions and lets the application decide which to keep (multi-victor). MongoDB uses last-write-wins — the most recent write automatically overwrites, potentially losing data. CouchDB’s approach is better for offline-first applications.

Real-World Task: Build an Offline Shopping List App

Design a database for a shopping list that syncs across devices — similar to Doda Browser’s bookmarks sync:

// Document structure
{
  "_id": "list_groceries",
  "type": "shopping_list",
  "name": "Weekly Groceries",
  "owner": "alice@example.com",
  "items": [
    {"name": "Milk", "quantity": 2, "checked": false},
    {"name": "Eggs", "quantity": 12, "checked": true},
    {"name": "Bread", "quantity": 1, "checked": false}
  ],
  "updated_at": "2026-06-07T15:00:00Z",
  "shared_with": ["bob@example.com"]
}

// View: Lists shared with a specific user
// Map function
function(doc) {
  if (doc.type === 'shopping_list' && doc.shared_with) {
    doc.shared_with.forEach(function(email) {
      emit(email, {name: doc.name, owner: doc.owner});
    });
  }
}

// View: Recently updated lists
// Map function
function(doc) {
  if (doc.type === 'shopping_list' && doc.updated_at) {
    emit(doc.updated_at, {name: doc.name, items_count: doc.items.length});
  }
}

FAQ

What is the difference between CouchDB and MongoDB?
CouchDB uses strict RESTful HTTP API, multi-master replication, and MapReduce views. MongoDB uses a custom binary protocol, replica sets (master-slave), and aggregation pipeline. CouchDB is better for offline-first/sync apps; MongoDB for real-time analytics.
Is CouchDB ACID compliant?
CouchDB provides per-document ACID guarantees using MVCC (Multi-Version Concurrency Control). Each document update is atomic. Multi-document transactions are not supported — design your documents accordingly.
What is PouchDB and how does it relate to CouchDB?
PouchDB is a JavaScript implementation of CouchDB that runs in the browser. It can sync bidirectionally with CouchDB, enabling offline-first web applications. Data is stored in IndexedDB or SQLite (WebSQL) in the browser.
How do I secure CouchDB?
Set admin credentials in local.ini, use HTTPS, configure CORS for web apps, create per-database user access with _security documents, and use a reverse proxy (Nginx) for production.
Can CouchDB handle large binary files?
Yes. CouchDB supports attachments — binary files stored alongside documents. Attachments are base64-encoded by default or use a streaming API for efficiency. Maximum document + attachment size is configurable (default 1GB).

Try It Yourself

Install CouchDB and explore these management endpoints:

# Check server status
curl http://admin:password@localhost:5984/

# Response:
# {"couchdb":"Welcome","version":"3.3.3","uuid":"...","vendor":{"name":"Apache Software Foundation"}}

# List all databases
curl http://admin:password@localhost:5984/_all_dbs

# Get database stats
curl http://admin:password@localhost:5984/shop

# Response:
# {"db_name":"shop","doc_count":2,"doc_del_count":0,"update_seq":4,
#  "purge_seq":0,"compact_running":false,"disk_size":12345,
#  "data_size":678,"instance_start_time":"..."}

# View active tasks (including replications)
curl http://admin:password@localhost:5984/_active_tasks

# Get database changes feed (poll for updates)
curl http://admin:password@localhost:5984/shop/_changes?since=now&feed=continuous

These REST API patterns are used by Doda Browser for cross-device sync and by Durga Antivirus Pro for distributing signature updates to offline-protected systems via CouchDB replication.

What’s Next

Congratulations on completing this CouchDB tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro