Databases9 min read

PostgreSQL vs MongoDB vs Redis: How to Actually Choose in 2026

PostgreSQL, MongoDB, and Redis solve different problems with different data models and durability guarantees. A practical comparison of what each one actually promises — and when each is the wrong tool.

Zeeshan Shahid
Zeeshan Shahid
January 12, 2026
Share:
PostgreSQL vs MongoDB vs Redis: How to Actually Choose in 2026

Most database comparisons line up PostgreSQL, MongoDB, and Redis and declare a winner. That framing is broken, because these three aren't running the same race. One is a relational database with strong transactional guarantees. One is a document store built around flexible schemas. One is an in-memory data structure server that most teams run alongside a primary database rather than instead of one.

The useful question isn't "which is fastest?" — it's "what does each one actually guarantee, and which of those guarantees does my application need?" This guide compares them on data model, consistency and durability, query capability, operational characteristics, and licensing.

A note on benchmark tables

You will find articles claiming precise latency figures for each of these databases — "5ms reads, 10ms writes." Treat them with suspicion. Database performance depends on schema design, index coverage, working-set size, hardware, network topology, query shape, and configuration. A number measured on someone else's workload tells you close to nothing about yours. The only benchmark that matters is one you run on your own data and access patterns. This article compares documented behaviour and design trade-offs instead.

Adoption: what developers actually run

The 2025 Stack Overflow Developer Survey asked respondents which databases they had done extensive development work in over the past year:

| Database | Share of all respondents | |----------|-------------------------| | PostgreSQL | 55.6% | | MySQL | 40.5% | | SQLite | 37.5% | | Microsoft SQL Server | 30.1% | | Redis | 28% | | MongoDB | 24% |

Among professional developers specifically, PostgreSQL rises to 58.2%.

Two things are worth noticing. First, these percentages sum to well over 100% — developers use several databases at once, which is the most important fact in this entire comparison. Second, Redis ranking above MongoDB doesn't make it a more popular primary database; it reflects that Redis is a near-universal caching layer sitting in front of something else.

Popularity is a weak signal for a technical decision, but it's a real one for hiring, documentation quality, and how fast you'll find an answer when something breaks at 2am.

The three data models

PostgreSQL: relational, with escape hatches

PostgreSQL stores data in tables with a declared schema, enforces relationships through foreign keys, and gives you the full SQL surface: joins, subqueries, window functions, CTEs, aggregates.

What surprises people returning after a few years is how much PostgreSQL has absorbed. It has a native JSONB binary document type with its own operators and indexes. It has full-text search. Through extensions it handles geospatial data (PostGIS) and vector similarity search for AI workloads (pgvector). Much of the "you need a specialist database for that" advice from a decade ago no longer holds.

-- Relational and document data in one query, one transaction
SELECT
  u.email,
  u.settings ->> 'theme'      AS theme,
  count(o.id)                 AS order_count,
  coalesce(sum(o.amount), 0)  AS lifetime_value
FROM users u
LEFT JOIN orders o
  ON o.user_id = u.id
 AND o.status = 'completed'
WHERE u.settings @> '{"notifications": true}'
GROUP BY u.id, u.email, u.settings
HAVING count(o.id) > 3
ORDER BY lifetime_value DESC;

That query joins across tables, filters on a JSON containment operator, aggregates, and then filters the aggregate — in one round trip, inside one transaction, against a consistent snapshot. That combination is the core of what PostgreSQL offers.

To make the JSON half fast you need a GIN index. This is the part people skip and then blame the database for:

-- Without this, @> containment falls back to a sequential scan
CREATE INDEX idx_users_settings ON users USING GIN (settings);

-- Partial index: only index the rows you actually query
CREATE INDEX idx_orders_pending ON orders (created_at)
WHERE status = 'pending';

PostgreSQL's index variety is a genuine advantage: B-tree for equality and ranges, GIN for containment and full-text, GiST for geometric and nearest-neighbour, BRIN for naturally ordered large tables. Choosing the right one matters more for real-world performance than the engine you're agonising over.

MongoDB: documents and flexible schemas

MongoDB stores BSON documents in collections. Data that would spread across five normalised tables can live in a single document, retrieved in one read with no join.

// One document holds what SQL would normalise across tables
{
  _id: ObjectId("..."),
  sku: "WIDGET-9",
  name: "Widget",
  attributes: { colour: "red", weight_g: 240, certifications: ["CE"] },
  variants: [
    { size: "S", stock: 12 },
    { size: "M", stock: 0 }
  ]
}

The pitch is schema flexibility. Documents in a collection don't need identical shapes, so you can add a field without a migration. This is genuinely useful when your data varies per record or is authentically hierarchical — product catalogues where every category carries different attributes are the honest example.

The aggregation pipeline covers analytical work:

db.orders.aggregate([
  { $match: { status: "completed", createdAt: { $gte: ISODate("2026-01-01") } } },
  { $group: { _id: "$customerId", totalSpent: { $sum: "$amount" }, orders: { $sum: 1 } } },
  { $match: { orders: { $gt: 3 } } },
  { $sort: { totalSpent: -1 } },
  { $limit: 100 }
]);

Two corrections to outdated criticism are worth making. MongoDB has supported multi-document ACID transactions since version 4.0 (4.2 for sharded clusters), so "MongoDB has no transactions" is simply wrong. And schema validation via JSON Schema is available if you want it — flexible need not mean unvalidated.

Schema flexibility is deferred, not removed

Skipping a migration doesn't delete the problem, it relocates it into your application code. If documents written in 2024 lack a field that documents written in 2026 have, every reader must handle both shapes — forever, or until you run a backfill. The schema still exists; it's just implicit and enforced nowhere. Plenty of teams who adopted MongoDB for schema freedom ended up hand-rolling validation and migrations regardless.

Redis: in-memory data structures

Redis keeps its dataset in memory and serves data structures rather than rows or documents: strings, hashes, lists, sets, sorted sets, streams, bitmaps, HyperLogLogs. You don't query Redis — you address a key and manipulate a structure.

# Cache with expiry
SETEX user:123:profile 3600 '{"name":"Ada","plan":"pro"}'

# Leaderboard — sorted set, ranked reads as a primitive
ZADD leaderboard 1500 "player:alice"
ZINCRBY leaderboard 50 "player:alice"
ZREVRANGE leaderboard 0 9 WITHSCORES

# Fixed-window rate limit
INCR api:user:123:requests
EXPIRE api:user:123:requests 60

The leaderboard is the clearest illustration of why Redis exists. Maintaining a live ranking in a relational database means either an ORDER BY across a large table on every read, or a denormalised rank column with write contention. Redis hands you a sorted set with ranked reads built in.

The rate limiter above has a bug

INCR followed by EXPIRE is two commands. If the process dies between them — or the key already existed without a TTL — you get a counter that never expires and a user locked out permanently. Use a Lua script or a transaction to make it atomic, and prefer a sliding window if bursts at window boundaries matter. Redis makes simple things simple and subtly wrong things easy.

Consistency and durability

This is where the real differences live, and it's the section most comparisons skip.

PostgreSQL is ACID with MVCC. Committed transactions are durable via write-ahead logging. Readers don't block writers and writers don't block readers. Default isolation is Read Committed; Serializable is available when you need it. When PostgreSQL says a transaction committed, that data survives a crash.

MongoDB offers tunable guarantees per operation through write concern and read concern. This is a real decision you must make consciously:

// Acknowledged by a majority of replicas AND flushed to the journal
db.orders.insertOne(doc, {
  writeConcern: { w: "majority", j: true }
});

With w: 1, a write acknowledged by the primary can be rolled back if that primary fails before replicating. Modern MongoDB defaults to w: "majority", which is far safer — but tunability means durability is your choice, and a wrong choice stays silent until a failover.

Redis is the one most often misunderstood. Redis persistence (RDB snapshots, AOF append-only file) is real but asynchronous by default. Under default AOF settings (everysec), a crash can lose up to a second of writes. Redis replication is asynchronous too, so a failover can drop acknowledged writes.

Key Takeaway

Redis is not a durable system of record under default configuration. It is a cache and a data structure server. If losing the last second of writes would be a business problem, that data belongs in PostgreSQL — with Redis in front of it if you need the speed.

Operational characteristics side by side

| | PostgreSQL | MongoDB | Redis | |---|---|---|---| | Data model | Relational + JSONB | BSON documents | In-memory structures | | Schema | Declared, enforced | Flexible, optional validation | None (key-addressed) | | Transactions | ACID, MVCC | Multi-document since 4.0 | Atomic commands, Lua, MULTI | | Default durability | WAL, synchronous commit | Tunable write concern | Async (RDB / AOF) | | Query language | SQL | MQL + aggregation pipeline | Commands per structure | | Joins | Native | $lookup, limited | None | | Scale-out story | Read replicas; sharding via extensions | Native sharding | Redis Cluster | | Dataset vs RAM | Larger than RAM is normal | Larger than RAM is normal | Working set should fit in RAM |

The scaling row needs nuance. PostgreSQL scales reads well with replicas and scales vertically further than most teams expect on modern hardware. Horizontal write sharding isn't in core PostgreSQL — you reach for Citus or shard at the application layer. MongoDB has native sharding, a genuine advantage if you need it and if you choose a good shard key. A bad shard key is painful to undo.

Redis's constraint is physical: memory costs money, and when your dataset outgrows RAM your options are eviction policies, sharding across a cluster, or a different tool.

Two more operational realities worth budgeting for. PostgreSQL's process-per-connection model makes connection pooling (PgBouncer, or a pooler built into your platform) close to mandatory once you run serverless functions or many app instances. And PostgreSQL's MVCC leaves dead tuples that autovacuum reclaims — usually invisible, occasionally the cause of a mysterious table-bloat incident.

Licensing: the part that bites later

A practical concern, not a philosophical one — and it has changed recently for two of the three.

PostgreSQL uses the permissive PostgreSQL License, similar to BSD/MIT. It's governed by a community rather than a company, so no vendor can change the terms on you. For many organisations this is the single strongest argument in its favour.

MongoDB is licensed under the SSPL (Server Side Public License), which the OSI does not recognise as open source. For most teams building an application this is a non-issue. If you intend to offer MongoDB as a service, read the licence carefully.

Redis has had an eventful few years:

  • Through early 2024: BSD-3-Clause.
  • March 2024: switched to dual RSALv2 / SSPLv1 — source-available, not OSI open source. AWS, Google, and Oracle backed Valkey, a BSD-licensed fork under the Linux Foundation.
  • May 2025: Redis 8.0 added AGPLv3 as a third option, restoring an OSI-approved path.

Redis today ships under a tri-licence: AGPLv3, RSALv2, or SSPLv1. If your organisation has a policy against AGPL or source-available licences, this matters — and Valkey is a drop-in alternative speaking the same protocol.

When not to use each

Usually more valuable than the feature lists.

Don't use PostgreSQL when

  • You need write throughput beyond what a single primary can absorb, and you're unwilling to run Citus or shard in the application.
  • Your data has no stable relationships and genuinely varies in shape per record.
  • You need sub-millisecond reads on hot keys. That's a cache, and PostgreSQL isn't one.
  • You're doing large-scale full-text search with relevance tuning, faceting, and typo tolerance. PostgreSQL's full-text search is good; Elasticsearch is a specialist.

Don't use MongoDB when

  • Your data is relational. If you're reaching for $lookup routinely, you've built a worse SQL engine.
  • You need cross-entity transactional guarantees as the normal case rather than the exception.
  • "Schema flexibility" is standing in for "we haven't modelled our data yet." That's a design deferral, not a database requirement.
  • Your team knows SQL and nothing about MongoDB's operational model. Shard keys and write concerns are real expertise.

Don't use Redis when

  • It holds the only copy of data you care about.
  • Your dataset substantially exceeds RAM — memory pricing will dominate the bill.
  • You need to query by value rather than by address. Redis has no ad-hoc query planner.
  • You're adding it "for performance" without a measured cache-hit problem. A cache is a second source of truth, and now you own invalidation bugs.

The real answer: most systems use more than one

Production systems rarely choose. A common, boring, well-understood architecture looks like this:

  • PostgreSQL as the system of record — users, orders, billing, anything requiring integrity.
  • Redis in front of it for caching, sessions, rate limiting, queues, and real-time structures like leaderboards.
  • A document store or search engine where a specific workload genuinely warrants one.

If you're starting today and unsure, start with PostgreSQL alone. It covers a wide range of workloads, its JSONB support lets you defer the document-store decision, and managed options like Supabase or your cloud provider's Postgres service remove most of the operational burden. Add Redis when you have a measured reason. Add MongoDB when you have a workload that is genuinely document-shaped.

The failure mode isn't picking the "wrong" database. It's running three at a scale where one would have done, and paying the operational tax on all three.

Before you migrate, check your indexes

A large share of "we outgrew PostgreSQL" stories turn out to be "we never added the right index" or "we never pooled our connections." Run EXPLAIN (ANALYZE, BUFFERS) on your slowest queries and look at pg_stat_statements before you rewrite your data layer. Migrations are expensive; indexes are cheap.

Tags:PostgreSQLMongoDBRedisDatabasesSQLNoSQLBackend
Zeeshan Shahid

Zeeshan Shahid

Founder, DevPages

Zeeshan builds and maintains DevPages, a hand-curated directory of developer tools. He writes about the tools in the catalog and the trade-offs between them.

22 articles published

Related Articles