Skip to content

What Is a Document Database?

10 min readMongoDBCouchDBFerretDBDatabases

A document database stores JSON-like documents instead of fixed-schema rows. Each document carries its own structure, so two records in the same collection can have completely different fields and adding a field takes no migration. MongoDB is the best-known example; CouchDB and FerretDB are the other two you are likely to meet.

"Do I actually need MongoDB, or is PostgreSQL fine?" If you've asked this question while setting up a new project, you're not alone. Every developer hits this decision point eventually. The answer depends on how your data is shaped and how you need to query it, not on which database has more hype.

This post breaks down when a document database genuinely makes your life easier, when a relational database is the better pick, and where PostgreSQL's JSONB blurs the line between the two.

Contents

What Is a Document Database

A relational database stores data in tables with fixed columns. Every row in a users table has the same fields. If you need a new field, you run a migration. Every row gets that column whether it needs it or not.

A document database stores JSON-like documents instead of rows. Each document is a self-contained unit with its own structure. Documents in the same collection can have completely different fields. No migrations needed to add a field. Nested objects and arrays are first-class citizens.

Here's a product catalog entry as a document:

json
{
  "name": "ThinkPad X1 Carbon",
  "category": "laptop",
  "price": 1429.99,
  "specs": {
    "cpu": "Intel i7-1365U",
    "ram": "16GB",
    "storage": "512GB SSD",
    "screenSize": "14 inch"
  },
  "tags": ["ultrabook", "business", "lightweight"]
}

And a t-shirt in the same collection:

json
{
  "name": "Classic Crew Tee",
  "category": "clothing",
  "price": 24.99,
  "specs": {
    "material": "100% cotton",
    "fit": "regular",
    "sizes": ["S", "M", "L", "XL"]
  },
  "colors": ["black", "white", "navy"],
  "tags": ["casual", "basics"]
}

Same collection, completely different specs fields. The laptop has ram and screenSize. The t-shirt has material and sizes. In a relational database, you would need a generic attributes table with key-value pairs, a separate table per category, or a bunch of nullable columns. In a document database, each document carries exactly the fields it needs.

When Document Databases Make Sense

Document databases aren't universally better. They solve specific problems well.

Data with highly variable structure. The product catalog example above is the classic case. When every category of item has different attributes, forcing them all into the same table schema creates more problems than it solves. Content management systems have the same pattern: a blog post has body and tags, a video has duration and resolution, a podcast has episodes and rss_url.

Rapid prototyping. When you're iterating on a product and the data model changes every week, not needing to write migrations is a real advantage. Store whatever your application produces, adjust the structure as requirements solidify, and formalize the schema later (or don't). There's real velocity in skipping the ALTER TABLE step during early development.

Event and activity logs. Log entries vary in structure. An API request log has endpoint, statusCode, and responseTime. A user action log has action, target, and metadata. A payment event has amount, currency, and paymentMethod. All are "events," but no two types share the same fields. Document databases handle this naturally with high write throughput.

Application objects that are already documents. If your code works with nested objects and arrays, storing them directly eliminates the translation layer between your application and your database. No ORM mapping nested objects into junction tables. No reassembling flattened rows into objects on read. The document is the object.

When PostgreSQL Is Better

Here's the honest part: for many projects, you don't need a document database.

Your data is relational. Users have orders. Orders have line items. Line items reference products. Products belong to categories. This is a graph of relationships, and relational databases are literally named after this pattern. Foreign keys, joins, and referential integrity constraints exist because this kind of data is common and important. Trying to model deeply relational data in a document database leads to either massive data duplication or complex application-side joins.

You need JOINs across entities. "Show me all orders placed by users who signed up this month, grouped by product category, with the average order value." That's one SQL query with a few joins. In a document database, it's multiple queries stitched together in application code.

You need transactions across multiple records. Transferring money between accounts, decrementing inventory while creating an order, updating a parent and child record together. Relational databases give you multi-row, multi-table ACID transactions by default. MongoDB supports multi-document transactions, but they're opt-in, have performance overhead, and the document model encourages designs that avoid them.

Your schema is well-defined and stable. If you know the shape of your data and it doesn't change much, a fixed schema with migrations is an advantage, not a burden. The schema documents your data model, validates inserts, and catches bugs before they reach production.

The PostgreSQL JSONB Middle Ground

Before reaching for a separate document database, consider that PostgreSQL can do both.

PostgreSQL's jsonb type stores binary JSON with full indexing support. You can query into nested fields, use GIN indexes for fast lookups, and mix structured columns with flexible JSON in the same table:

sql
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  category VARCHAR(100) NOT NULL,
  price NUMERIC(10,2) NOT NULL,
  specs JSONB,
  tags JSONB DEFAULT '[]'
);

INSERT INTO products (name, category, price, specs, tags) VALUES
  ('ThinkPad X1', 'laptop', 1429.99,
   '{"cpu": "i7", "ram": "16GB", "screenSize": "14 inch"}',
   '["ultrabook", "business"]'),
  ('Classic Tee', 'clothing', 24.99,
   '{"material": "cotton", "fit": "regular", "sizes": ["S","M","L"]}',
   '["casual", "basics"]');

Query into the JSON:

sql
-- Find laptops with 16GB RAM
SELECT name, price, specs->>'ram' AS ram
FROM products
WHERE category = 'laptop'
  AND specs->>'ram' = '16GB';

-- Find products tagged "business"
SELECT name, price
FROM products
WHERE tags @> '"business"';

For many projects, this is enough. You get document flexibility for the fields that need it, relational structure for the fields that don't, and everything lives in one database with one backup strategy, one connection pool, and one set of operational knowledge.

The trade-off: querying deeply nested JSONB is more verbose than MongoDB's query language, and you still need migrations when your fixed columns change. But for a team already running PostgreSQL, adding a jsonb column is simpler than adding and operating a second database.

Your Options

If you do need a dedicated document database, here are the three main choices.

MongoDB

The standard. Largest ecosystem, most mature tooling, the strongest query language and aggregation pipeline of any document database. The mongodb npm package works with every major language and framework. MongoDB Atlas provides a fully managed cloud option with a free tier.

The licensing question: MongoDB uses SSPL, which prevents you from offering it as a managed service without open-sourcing your entire stack. For most application developers, this isn't a practical issue. For platform builders, it might be.

Read the full walkthrough: Getting Started with MongoDB

FerretDB

MongoDB's query API on PostgreSQL. Same mongodb:// connection string, same driver, same query syntax. Your documents get stored as JSONB in PostgreSQL tables. Apache 2.0 licensed, no SSPL concerns.

The catch: it doesn't support everything MongoDB supports yet. No $lookup, no change streams, no text indexes. For core CRUD and basic aggregation, it produces identical results to MongoDB. If you're already a PostgreSQL shop and want the document API without a second database system, FerretDB is compelling.

Read the full walkthrough: Getting Started with FerretDB

Deeper comparison: MongoDB vs FerretDB

CouchDB

Built for replication. Where MongoDB focuses on flexible queries, CouchDB tackles keeping data consistent across distributed systems. Every operation is an HTTP request. Built-in multi-master replication with automatic conflict resolution.

CouchDB is the right pick for offline-first applications, multi-site deployments, and edge computing where devices sync data when they come online. If your primary concern is query flexibility and aggregation, MongoDB is a better fit. If your primary concern is reliable data synchronization across unreliable networks, CouchDB was designed for that.

Read the full walkthrough: Getting Started with CouchDB

Seeing It Work

The flexibility is easiest to see in one query. Store three products with completely different specs shapes in the same collection, then read them back:

text
Products under $100:
  Classic Tee - $24.99

Product specs (all different shapes):
  ThinkPad X1: {"cpu":"i7","ram":"16GB","screenSize":"14 inch"}
  Classic Tee: {"material":"cotton","fit":"regular"}
  Mechanical Keyboard: {"switches":"Cherry MX Brown","layout":"TKL","backlit":true}

Three products, three completely different specs shapes, all in the same collection, all queryable. No migration, no nullable columns.

Want to build it yourself? Run MongoDB locally with the Layerbase CLI, then follow Getting Started with MongoDB for the full walkthrough. Hosted, the document engine is FerretDB: MongoDB itself is not creatable in the cloud for licensing reasons, and the MongoDB card in the create flow provisions FerretDB, which gives you the same MongoDB API on PostgreSQL and the same wire protocol your driver already speaks.

FAQ

What is a document database in simple terms?

It is a database that stores records as JSON-like documents rather than as rows in a fixed table. Each document brings its own shape, so a laptop record can carry ram and screenSize while a t-shirt record in the same collection carries material and sizes, and neither one needs a migration to exist.

Is a document database the same as a NoSQL database?

Not quite. "NoSQL" is a catch-all for anything that is not a relational database, which sweeps in key-value stores like Redis, wide-column stores like Cassandra, and graph databases too. A document database is one family inside that bucket, specifically the one that stores JSON-shaped documents. Every document database is NoSQL; most NoSQL databases are not document databases.

Is MongoDB a document database?

Yes, and it is the one most people mean when they use the term. It has the largest ecosystem, the most mature tooling, and the strongest aggregation pipeline of the family. CouchDB and FerretDB are document databases too, with different priorities: replication for CouchDB, and the MongoDB API on PostgreSQL for FerretDB.

When should I use a document database instead of PostgreSQL?

When your data genuinely varies in shape from record to record, when you are iterating fast enough that migrations are slowing you down, or when your application objects are already nested and you would rather not translate them into tables and back. If instead your data is full of relationships you need to join across, or you need transactions spanning several records, PostgreSQL is the better tool and it is not close.

Can PostgreSQL store documents?

Yes. The jsonb type stores binary JSON with real indexing, so you can keep fixed columns for the stable parts of your schema and a JSON column for the parts that vary, then query into the nested fields with GIN indexes behind them. For a team already running PostgreSQL, that is usually simpler than adding and operating a second database. The trade is that deep JSONB queries are more verbose than MongoDB's query language.

Do document databases support joins and transactions?

Some, but they are not the strong suit. MongoDB has $lookup for joins and supports multi-document transactions, though both are opt-in, carry overhead, and cut against a data model that is meant to keep related data inside one document. FerretDB does not support $lookup at all yet. If joins and multi-record transactions are central to your application, that is a signal pointing back at a relational database.

Wrapping Up

Document databases store flexible, self-describing JSON documents instead of fixed-schema rows. They work well for variable-structure data, rapid prototyping, event logs, and application objects that are already nested.

But they're not always the right tool. If your data is relational, if you need JOINs and multi-record transactions, or if your schema is stable, PostgreSQL is probably the better choice. And PostgreSQL's JSONB gives you document-like flexibility without a second database when you need it.

If you do want a document database: MongoDB is the default for most use cases, FerretDB gives you the MongoDB API on PostgreSQL, and CouchDB handles distributed replication better than anything else.

When you're ready to build, Layerbase Cloud provisions managed FerretDB or CouchDB in seconds, next to PostgreSQL and the rest of the cloud catalog. MongoDB itself is not creatable in the cloud for licensing reasons; the MongoDB card in the create flow provisions FerretDB on the same wire protocol. Prefer to prototype locally first? The Layerbase CLI runs MongoDB itself, and every other engine, on your machine with no Docker.