Apache CouchDB: The Complete Developer’s Cheat Sheet

Introduction: What is CouchDB and Why It Matters

Apache CouchDB is an open-source, document-oriented NoSQL database that uses JSON documents, JavaScript for MapReduce indexing, and HTTP for its API. CouchDB is designed for reliability and features seamless multi-master synchronization across devices.

Why It Matters:

  • Offline-First Architecture: Built from the ground up for applications that need to work regardless of network connectivity
  • Bi-directional Replication: Synchronizes data reliably between multiple instances
  • Schema-free Documents: Stores data in flexible, JSON-based documents without enforcing schemas
  • RESTful HTTP API: Interacts with your data using standard HTTP methods
  • Eventual Consistency: Handles conflicts with revision tracking and customizable conflict resolution

Core Concepts and Principles

Document Structure

CouchDB stores data as JSON documents with the following characteristics:

{
  "_id": "unique_document_id",
  "_rev": "revision_id",
  "field1": "value1",
  "field2": 42,
  "field3": {
    "nested": "object"
  },
  "field4": ["array", "of", "values"]
}
  • _id: Unique identifier for the document (auto-generated UUID if not specified)
  • _rev: Revision number (CouchDB generated, used for conflict detection)
  • All other fields are user-defined and can contain any valid JSON data

Database Concepts

ConceptDescription
DatabaseContainer for documents and design documents
DocumentJSON object with unique _id field
Design DocumentSpecial document starting with _design/ that contains views, filters, and other functions
ViewMapReduce function pair for indexing and querying documents
ReplicationProcess of synchronizing databases between CouchDB instances
Changes FeedStream of document changes in chronological order

HTTP Status Codes

Status CodeMeaning
200 OKRequest completed successfully
201 CreatedDocument created successfully
202 AcceptedRequest accepted (for background operations)
304 Not ModifiedDocument wasn’t modified since specified revision
400 Bad RequestInvalid request format
401 UnauthorizedAuthentication required
403 ForbiddenOperation not permitted
404 Not FoundDocument or endpoint not found
409 ConflictDocument update conflict
412 Precondition FailedDatabase already exists or revision check failed
500 Internal Server ErrorServer error

Step-by-Step Processes

Setting Up CouchDB

  1. Install CouchDB:

    • Docker: docker run -p 5984:5984 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password couchdb:latest
    • Ubuntu/Debian: apt-get install couchdb
    • macOS: brew install couchdb
    • Windows: Download installer from couchdb.apache.org
  2. Verify Installation:

    curl http://localhost:5984/
    # Expected response: {"couchdb":"Welcome","version":"3.x.x",...}
    
  3. Set Up Admin User (if not using Docker environment variables):

    curl -X PUT http://localhost:5984/_users
    curl -X PUT http://localhost:5984/_replicator
    curl -X PUT http://localhost:5984/_global_changes
    
    # Create admin user
    curl -X PUT http://localhost:5984/_node/nonode@nohost/_config/admins/admin -d '"password"'
    

Basic Database Operations

  1. Create a Database:

    curl -X PUT http://admin:password@localhost:5984/mydb
    # Response: {"ok":true}
    
  2. Delete a Database:

    curl -X DELETE http://admin:password@localhost:5984/mydb
    # Response: {"ok":true}
    
  3. List All Databases:

    curl http://admin:password@localhost:5984/_all_dbs
    # Response: ["_replicator","_users","mydb"]
    

Document Operations

  1. Create a Document:

    # With auto-generated ID
    curl -X POST -H "Content-Type: application/json" \
         http://admin:password@localhost:5984/mydb \
         -d '{"name":"John","age":30}'
    
    # With specified ID
    curl -X PUT -H "Content-Type: application/json" \
         http://admin:password@localhost:5984/mydb/doc1 \
         -d '{"name":"Jane","age":25}'
    
  2. Retrieve a Document:

    curl http://admin:password@localhost:5984/mydb/doc1
    # Response: {"_id":"doc1","_rev":"1-xx","name":"Jane","age":25}
    
  3. Update a Document:

    # First get the current revision
    curl http://admin:password@localhost:5984/mydb/doc1
    
    # Then update with the revision
    curl -X PUT -H "Content-Type: application/json" \
         http://admin:password@localhost:5984/mydb/doc1 \
         -d '{"_rev":"1-xx","name":"Jane","age":26}'
    
  4. Delete a Document:

    # First get the current revision
    curl http://admin:password@localhost:5984/mydb/doc1
    
    # Then delete with the revision
    curl -X DELETE http://admin:password@localhost:5984/mydb/doc1?rev=2-xx
    

Creating and Using Views

Creating a Design Document with Views

curl -X PUT -H "Content-Type: application/json" \
     http://admin:password@localhost:5984/mydb/_design/mydesign \
     -d '{
       "views": {
         "by_name": {
           "map": "function(doc) { emit(doc.name, doc); }"
         },
         "count_by_age": {
           "map": "function(doc) { if(doc.age) { emit(doc.age, 1); } }",
           "reduce": "_count"
         }
       }
     }'

Querying Views

# Basic view query
curl http://admin:password@localhost:5984/mydb/_design/mydesign/_view/by_name

# With key filtering
curl http://admin:password@localhost:5984/mydb/_design/mydesign/_view/by_name?key="Jane"

# Range queries
curl http://admin:password@localhost:5984/mydb/_design/mydesign/_view/count_by_age?startkey=20&endkey=30

# Include documents
curl http://admin:password@localhost:5984/mydb/_design/mydesign/_view/by_name?include_docs=true

# Using reduce
curl http://admin:password@localhost:5984/mydb/_design/mydesign/_view/count_by_age?group=true

Key Techniques and Methods

Using Mango Queries (JSON-based queries)

curl -X POST -H "Content-Type: application/json" \
     http://admin:password@localhost:5984/mydb/_find \
     -d '{
       "selector": {
         "age": {"$gt": 25}
       },
       "fields": ["_id", "name", "age"],
       "sort": [{"age": "asc"}],
       "limit": 10
     }'

Creating Indexes for Mango Queries

curl -X POST -H "Content-Type: application/json" \
     http://admin:password@localhost:5984/mydb/_index \
     -d '{
       "index": {
         "fields": ["age", "name"]
       },
       "name": "age-name-index",
       "type": "json"
     }'

Replication

# One-time replication from source to target
curl -X POST -H "Content-Type: application/json" \
     http://admin:password@localhost:5984/_replicate \
     -d '{
       "source": "http://admin:password@localhost:5984/mydb",
       "target": "http://admin:password@localhost:5984/mydb_copy"
     }'

# Continuous replication
curl -X POST -H "Content-Type: application/json" \
     http://admin:password@localhost:5984/_replicate \
     -d '{
       "source": "http://admin:password@localhost:5984/mydb",
       "target": "http://admin:password@localhost:5984/mydb_copy",
       "continuous": true
     }'

Using Changes Feed

# Basic changes feed
curl http://admin:password@localhost:5984/mydb/_changes

# Continuous changes feed (long polling)
curl http://admin:password@localhost:5984/mydb/_changes?feed=longpoll

# Filter changes by document IDs
curl -X POST -H "Content-Type: application/json" \
     http://admin:password@localhost:5984/mydb/_changes?filter=_doc_ids \
     -d '{"doc_ids": ["doc1", "doc2"]}'

# Include documents in changes feed
curl http://admin:password@localhost:5984/mydb/_changes?include_docs=true

Common Challenges and Solutions

ChallengeSolution
Document conflictsImplement proper conflict resolution strategy with _conflicts field
Performance issues with viewsUse appropriate indexing, limit result sets, use stale=ok for non-critical queries
Handling large result setsUse pagination with skip/limit parameters or startkey/endkey ranges
Slow replicationUse filtered replication to sync only necessary documents
Storage growthUse database compaction regularly to reclaim space
Authentication failuresCheck credentials, ensure user has correct permissions

Conflict Resolution

// 1. Fetch document with conflicts
fetch('http://admin:password@localhost:5984/mydb/doc1?conflicts=true')
  .then(response => response.json())
  .then(doc => {
    if (doc._conflicts) {
      // 2. Fetch all conflict revisions
      Promise.all(doc._conflicts.map(rev => 
        fetch(`http://admin:password@localhost:5984/mydb/doc1?rev=${rev}`)
          .then(response => response.json())
      )).then(conflictDocs => {
        // 3. Implement your conflict resolution strategy
        const resolvedDoc = resolveConflicts(doc, conflictDocs);
        
        // 4. Save the resolved document
        fetch(`http://admin:password@localhost:5984/mydb/doc1?rev=${doc._rev}`, {
          method: 'PUT',
          headers: {'Content-Type': 'application/json'},
          body: JSON.stringify(resolvedDoc)
        });
        
        // 5. Delete conflict revisions
        doc._conflicts.forEach(rev => {
          fetch(`http://admin:password@localhost:5984/mydb/doc1?rev=${rev}`, {
            method: 'DELETE'
          });
        });
      });
    }
  });

Database Compaction

# Compact a single database
curl -X POST http://admin:password@localhost:5984/mydb/_compact

# Compact a view
curl -X POST http://admin:password@localhost:5984/mydb/_compact/mydesign

# Compact all databases
curl -X POST http://admin:password@localhost:5984/_db_updates

Best Practices

Document Design

  • Keep documents small: Large documents consume more memory and are slower to transfer
  • Use meaningful IDs: When possible, use IDs that have meaning in your domain
  • Include document type: Add a type field to distinguish between different document types
  • Avoid deeply nested structures: Flatten document structure when possible
  • Denormalize when appropriate: Include related data to avoid multiple queries

View Design

  • Create specialized views: Design views for specific query patterns
  • Use compound keys: Emit arrays as keys for hierarchical data
  • Optimize reduce functions: Built-in reduce functions (_sum, _count, _stats) are highly optimized
  • Use include_docs=true sparingly: Only use when you need the entire document
  • Index only what you need: Only emit the data you’ll query

Security Best Practices

  • Use HTTPS for all CouchDB connections in production
  • Set up proper admin accounts with strong passwords
  • Implement database-level security with validation functions
  • Use proper authentication methods (cookie auth, JWT, proxy auth)
  • Set up appropriate user roles and permissions

CouchDB with PouchDB (Client-Side)

Basic PouchDB Usage

// Create a local database
const localDB = new PouchDB('mydb');

// Create a remote database connection
const remoteDB = new PouchDB('http://admin:password@localhost:5984/mydb');

// Create a document
localDB.put({
  _id: 'doc1',
  name: 'John',
  age: 30
}).then(response => {
  console.log(response);
}).catch(err => {
  console.error(err);
});

// Get a document
localDB.get('doc1').then(doc => {
  console.log(doc);
}).catch(err => {
  console.error(err);
});

// Delete a document
localDB.get('doc1').then(doc => {
  return localDB.remove(doc);
}).then(response => {
  console.log(response);
}).catch(err => {
  console.error(err);
});

// Set up sync
localDB.sync(remoteDB, {
  live: true,
  retry: true
}).on('change', function(change) {
  console.log('change', change);
}).on('error', function(err) {
  console.error('sync error', err);
});

Using PouchDB with Map/Reduce

// Create a design document
localDB.put({
  _id: '_design/mydesign',
  views: {
    by_name: {
      map: function(doc) {
        emit(doc.name, doc);
      }.toString()
    }
  }
}).then(() => {
  // Query the view
  return localDB.query('mydesign/by_name', {
    key: 'John',
    include_docs: true
  });
}).then(result => {
  console.log(result.rows);
}).catch(err => {
  console.error(err);
});

Common CouchDB Configuration Options

ConfigurationDescriptionDefaultExample Value
max_document_sizeMaximum document size in bytes8MB4194304 (4MB)
max_dbs_openMaximum number of open databases500100
delayed_commitsWhether to use delayed commitstruefalse
uuids/algorithmUUID generation algorithmrandomsequential
httpd/enable_corsEnable CORSfalsetrue
cors/originsAllowed CORS origins*http://localhost:8000
log/levelLogging verbosityinfodebug
couch_httpd_auth/timeoutSession timeout in seconds6003600

Resources for Further Learning

Official Documentation

Tools

  • Fauxton – Web-based administration interface for CouchDB
  • PouchDB – JavaScript client library implementing CouchDB protocols
  • Nano – Official CouchDB client for Node.js
  • cURL – Command-line tool for interacting with the CouchDB API

Community Resources

Books and Learning Resources

  • “CouchDB: The Definitive Guide” by J. Chris Anderson, Jan Lehnardt, and Noah Slater
  • “Offline First Web Development” by Daniel Sauble
  • “CouchDB and Node.js” by Joe Lennon
  • “PouchDB Essentials” by Nolan Lawson
Scroll to Top