Apache CouchDB
File: couchdb.py
Purpose: Production-ready document database with HTTP API
Implementation Details
class CouchDBService(DatabaseService):
def __init__(self, url: str, username: str, password: str):
self.couch = couchdb.Server(url)
self.couch.resource.credentials = (username, password)
Characteristics
- Storage: Disk-based B-tree
- Persistence: Full durability with append-only writes
- Performance: Good for document-oriented workloads
- Revision Tracking: Native
_revfield with MVCC - Auto-initialization: Creates databases on first access
Configuration
# .env or environment variables
DATABASE_PROVIDER=couchdb
COUCHDB_URL=http://localhost:5984
COUCHDB_USER=admin
COUCHDB_PASSWORD=password
Docker Setup
# docker-compose.yml includes:
services:
couchdb:
image: couchdb:latest
ports:
- "5984:5984"
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=password
Special Considerations
1. Database Creation
Automatically creates databases if they don't exist:
# In save() method:
if db_name not in self.couch:
self.couch.create(db_name)
2. Revision Conflicts
CouchDB uses MVCC (Multi-Version Concurrency Control):
- Must include current
_revwhen updating documents - Returns 409 status on conflict
- Implementation handles this by fetching current
_revbefore update:
try:
existing = db[doc_id]
doc["_rev"] = existing["_rev"]
except couchdb.http.ResourceNotFound:
pass # New document, no _rev needed
3. Listing Documents
Uses _all_docs view with include_docs=True:
for row in db.view("_all_docs", include_docs=True):
documents.append(row.doc)
4. ID Storage
Stores document ID in both:
- CouchDB's native
_idfield - Application's
_idfield (for consistency)
Production Recommendations
- Enable authentication (never use admin party mode)
- Configure replication for high availability
- Set up regular backups (CouchDB replication protocol)
- Monitor disk space (compaction needed periodically)
- Use clustering for horizontal scaling
Example Usage
from services.database_service import get_database_service
from config import Settings
settings = Settings(
DATABASE_PROVIDER="couchdb",
COUCHDB_URL="http://localhost:5984",
COUCHDB_USER="admin",
COUCHDB_PASSWORD="password"
)
db = get_database_service(settings)
# Save a document
result = db.save("agents", "agent-1", {"name": "My Agent", "code": "..."})
print(result) # {"id": "agent-1", "rev": "1-abc123..."}
# Update the document
agent = db.get("agents", "agent-1")
agent["name"] = "Updated Agent"
result = db.save("agents", "agent-1", agent)
print(result) # {"id": "agent-1", "rev": "2-def456..."}
Common Operations
Starting CouchDB with Docker
# Start CouchDB
docker run -d \
--name gofannon-couchdb \
-p 5984:5984 \
-e COUCHDB_USER=admin \
-e COUCHDB_PASSWORD=password \
couchdb:latest
# Verify it's running
curl http://admin:password@localhost:5984/
Accessing Fauxton UI
Open http://localhost:5984/_utils in your browser to access the Fauxton web interface.
Creating a Database Manually
curl -X PUT http://admin:password@localhost:5984/agents
Viewing Documents
curl http://admin:password@localhost:5984/agents/_all_docs?include_docs=true
Troubleshooting
Connection Refused
Error: ConnectionError: Failed to connect to CouchDB
Solutions:
- Verify CouchDB is running:
curl http://localhost:5984 - Check the URL in your configuration
- Ensure Docker container is running:
docker ps | grep couchdb
Authentication Failed
Error: Unauthorized: Invalid credentials
Solutions:
- Verify COUCHDB_USER and COUCHDB_PASSWORD are correct
- Check CouchDB logs:
docker logs gofannon-couchdb - Ensure admin party mode is disabled
Document Conflict
Error: 409 Conflict: Document update conflict
Solutions:
- Implementation automatically handles this by fetching current
_rev - If you still see this, verify you're using the latest version of the code
- Manually fetch the document and retry the update
Disk Space Issues
Error: Database writes failing or slow
Solutions:
- Check disk space:
df -h - Run compaction:
curl -X POST http://admin:password@localhost:5984/agents/_compact - Set up automatic compaction in CouchDB configuration
Performance Tuning
Views and Indexes
Create views for common query patterns:
// Example design document for querying agents by name
{
"_id": "_design/agents",
"views": {
"by_name": {
"map": "function(doc) { if(doc.name) { emit(doc.name, doc); } }"
}
}
}
Compaction
Set up automatic compaction in local.ini:
[compactions]
_default = [{db_fragmentation, "70%"}, {view_fragmentation, "60%"}]
Replication
Set up replication for high availability:
curl -X POST http://admin:password@localhost:5984/_replicate \
-H "Content-Type: application/json" \
-d '{
"source": "http://localhost:5984/agents",
"target": "http://backup-server:5984/agents",
"continuous": true
}'
Security Best Practices
- Authentication: Always require authentication
- SSL/TLS: Use HTTPS in production (configure with reverse proxy)
- Least Privilege: Create application-specific users with limited permissions
- Firewall: Restrict access to CouchDB ports
- Audit Logging: Enable audit logging for compliance
- Regular Updates: Keep CouchDB updated with security patches
Migration from Memory Database
from services.database_service import get_database_service
from config import Settings
# Source: Memory
source_settings = Settings(DATABASE_PROVIDER="memory")
source_db = get_database_service(source_settings)
# Target: CouchDB
target_settings = Settings(
DATABASE_PROVIDER="couchdb",
COUCHDB_URL="http://localhost:5984",
COUCHDB_USER="admin",
COUCHDB_PASSWORD="password"
)
target_db = get_database_service(target_settings)
# Migrate all collections
collections = ["agents", "deployments", "users", "sessions", "tickets", "demos"]
for collection in collections:
documents = source_db.list_all(collection)
for doc in documents:
doc_id = doc.pop("_id")
target_db.save(collection, doc_id, doc)
Related Documentation
- Configuration - Database provider configuration
- Schema - Collection and document schemas
- Testing - Testing strategies
- Troubleshooting - Common issues and solutions
- CouchDB Official Documentation
Last Updated: 2026-01-11