Siddhant Deval
Siddhant DevalAuthor
Senior Full-Stack Engineer·Aug 23, 2026·16 min read

The Database Selection Playbook: From Workload to Production Decision

A production database selection is a structured elimination process — not a feature race. This article applies the 5-step elimination framework (workload → consistency → scale → expertise → cost) to every paradigm in the series, with worked system design interview examples for Twitter, Uber, and a RAG chatbot.

The Database Selection Playbook: From Workload to Production Decision

Selecting the right database is a foundational architectural decision; data gravity ultimately dictates the scalability and resilience of an application — choose the paradigm first, the product second. The broken pattern in database selection is starting with a product name: "Should we use Mongo or Postgres?" This question has no correct answer without knowing the workload shape, consistency requirement, scale horizon, team expertise, and cost constraint. This article gives you the structured elimination process that makes the answer objective — and shows you how to apply it in production architectural reviews and system design interviews.

1. The 5-Step Elimination Process

The goal of each step is to eliminate paradigms that cannot serve your workload, not to rank the remaining ones. By Step 5, you should have a shortlist of 1–3 products.

Step 1 — Classify the Workload

From Part 1's taxonomy: OLTP, Search, Graph, Cache/Session, Vector, or Time-Series? Most production systems have a dominant workload class and secondary access patterns. Optimize for the dominant class — serve the secondaries with extensions or a second store only if the primary paradigm cannot.

Step 2 — Determine the Minimum Acceptable Consistency

ScenarioRequired ConsistencyWhy
Payment processing, inventory reservationStrong (serializable)Double-spend, oversell impossible
User profile updatesRead-your-own-writesUser must see their own change
Social feed, notificationsEventualLag of seconds is acceptable
Search index, analyticsEventualStale by design — indexing lag expected
Rate limiting, countersEventual with atomic opsRedis INCR is atomic, not transactional

Step 3 — Project the Scale Horizon (12 months)

Scale signals that determine paradigm fit:
  Row/document count:
    < 10M     → Any paradigm works. Choose the simplest.
    10M–100M  → B-tree index efficiency matters. Postgres still dominant.
    100M–1B   → Partitioning or distributed SQL required for Postgres.
    > 1B      → Distributed paradigm (Cassandra, DynamoDB, CockroachDB) mandatory.

  Write throughput:
    < 10K writes/sec    → Postgres with PgBouncer handles this.
    10K–100K writes/sec → Cassandra or DynamoDB territory.
    > 100K writes/sec   → Distributed NoSQL with horizontal sharding.

  Vector count:
    < 10M  → pgvector (HNSW) handles at < 100ms P99.
    > 10M  → Dedicated vector store required.

Step 4 — Account for Team Expertise

Operational ramp estimate for an unfamiliar paradigm:
  Redis:          2–4 weeks (simple mental model, good docs)
  MongoDB:        4–6 weeks (document modeling discipline)
  Elasticsearch:  6–8 weeks (mapping discipline, JVM ops)
  Cassandra:      8–12 weeks (LSM-tree ops, compaction tuning, tombstones)
  CockroachDB:    8–12 weeks (Raft, serialization retries, clock skew)
  Neo4j:          4–6 weeks (Cypher, graph modeling)
Performance / Safety Warning
A team of MySQL experts choosing CockroachDB for a new service adds 8–12 weeks of operational ramp before they can safely respond to production incidents. If the business timeline doesn't accommodate this, the correct choice is the paradigm the team already operates well — even if it is theoretically suboptimal.

Step 5 — Calculate Total Cost of Ownership

Store$0–$500/mo range$500–$5K/mo range> $5K/mo range
PostgreSQL (managed — Supabase/RDS)t3.medium: ~$25/modb.r6g.xlarge: ~$400/moMulti-AZ + replicas: $1K–$5K
MongoDB AtlasM10: ~$60/moM40: ~$420/moM80+: ~$2K+/mo
DynamoDB (on-demand)< 5M ops/day: < $100/mo50M ops/day: ~$1K/mo500M ops/day: ~$10K/mo
CockroachDB (Dedicated)3-node 2vCPU: ~$450/mo3-node 8vCPU: ~$1.8K/moMulti-region: $5K–$15K
Elasticsearch (managed)t3.small.search: ~$50/mor6g.large.search: ~$600/mor6g.4xlarge: ~$3K+/mo
Redis (ElastiCache)cache.t3.micro: ~$12/mocache.r6g.large: ~$120/mocache.r6g.4xlarge: ~$1K+/mo

2. Full Paradigm Decision Table

Full paradigm decision matrix — rows show workload patterns, columns show paradigm fit (strong/conditional/weak) with scale threshold annotations per cell.
Full paradigm decision matrix — rows show workload patterns, columns show paradigm fit (strong/conditional/weak) with scale threshold annotations per cell.
Workload PatternRelational SQLDocument NoSQLDistributed SQLSpecialized Store
Point reads/writes (OLTP)✅ Strong (< 100M rows)✅ Strong✅ Strong (any scale)⚠️ Redis (sub-ms)
Complex joins / reporting✅ Strong❌ Weak ($lookup expensive)✅ Strong❌ Weak
Flexible/evolving schema⚠️ Conditional (JSONB)✅ Strong⚠️ Conditional❌ Weak
Full-text search⚠️ Conditional (tsvector, < 5M)⚠️ Atlas Search⚠️ Conditional✅ Elasticsearch
Graph traversal (3+ hops)❌ Weak (recursive CTE, O(n³))❌ Weak❌ Weak✅ Neo4j
Sub-millisecond key lookup❌ Weak (5ms+ overhead)❌ Weak❌ Weak✅ Redis
Extreme write throughput (> 100K/s)❌ Weak⚠️ DynamoDB⚠️ CockroachDB✅ Cassandra
Multi-region HA + SQL❌ (manual sharding)✅ Strong (CockroachDB)
Vector similarity / RAG⚠️ pgvector (< 10M)⚠️ Atlas (< 5M)⚠️ pgvector✅ Qdrant / Pinecone

3. System Design Interview Application

The pattern that earns architectural credit in a system design interview: Access Pattern → Paradigm → Product → Scale Justification. Never open with a product name.

"Design Twitter / X" — Database Narration

1. Users and profiles: OLTP, point reads, strong consistency for auth
   → PostgreSQL (relational, ACID, pgvector for ML features)

2. Tweets and timeline: high-volume writes, fan-out reads, eventual consistency ok
   → Redis (in-memory sorted sets for timeline cache)
   → Cassandra (write-heavy, time-series, wide-row for tweet storage at billions)

3. Search (full-text tweet search): inverted index, relevance ranking
   → Elasticsearch (full-text, BM25 scoring, CDC-synced from Cassandra)

4. Social graph (follow/follower): 3+ hop traversal for recommendations
   → Neo4j (graph DB for follow relationship traversal)
   → OR: Postgres with materialized follower counts if traversal stays ≤ 2 hops

"Design a RAG Chatbot" — Database Narration

1. Document/chunk storage: structured metadata + raw text
   → PostgreSQL (title, source URL, created_at, chunk_index as typed columns)

2. Vector embeddings: similarity search for retrieval
   → pgvector if < 10M chunks (HNSW index, stays inside Postgres — no new infra)
   → Qdrant if > 10M chunks or hybrid BM25+dense search required

3. Conversation history: session-based, read-heavy, TTL expiry
   → Redis (Hash per conversation, TTL = 24 hours)

4. Usage/billing metadata: OLTP, ACID, FK constraints
   → PostgreSQL (same instance as document store — one Postgres, many purposes)

"Design Uber" — Database Narration

1. Driver/rider profiles: OLTP, strong consistency
   → PostgreSQL

2. Real-time driver location: high-write, TTL expiry, geospatial lookup
   → Redis Geosearch (GEOADD / GEORADIUS) — sub-millisecond at any scale
   → Fallback: PostGIS for historical trip analysis (not real-time)

3. Trip ledger (billing, receipts): ACID, financial transactions
   → PostgreSQL (serializable isolation, FK constraints, pg_audit for compliance)

4. Surge pricing regions: geospatial, computed in near-real-time
   → Redis (pre-computed per-region surge multiplier, refreshed every 30 seconds)

5. Trip history: append-only, time-range queries, billions of rows
   → Cassandra (time-series, wide-row, TWCS compaction)

4. Anti-Pattern Catalog

typescript
// Anti-pattern 1: MongoDB for everything
// Symptom: JOIN-heavy reporting now done in application code with N+1 fetch loops
const orders = await Order.find({})  // fetch all orders
const users = await Promise.all(orders.map(o => User.findById(o.userId)))  // N queries!
// Fix: PostgreSQL — the relational model exists precisely for this access pattern

// Anti-pattern 2: Elasticsearch as a primary database
await elasticsearch.index({ index: 'orders', id: orderId, body: { ... } })
// No ACID. No FK constraints. Index propagation is eventually consistent.
// An order write can appear "committed" to the app but not yet searchable.
// Fix: Postgres as primary → CDC → Elasticsearch for search-only reads

// Anti-pattern 3: Redis as durable store without AOF
await redis.set(`order:${orderId}`, JSON.stringify(order))
// Redis restarts at 3 AM. RDB snapshot from 2 hours ago. 2 hours of orders gone.
// Fix: appendonly yes + appendfsync everysec in redis.conf

// Anti-pattern 4: Distributed SQL for a single-region MVP
// CockroachDB Dedicated, 3-node: $450/month for a service with 100 active users
// Postgres on Supabase: $25/month for the same workload
// Fix: choose the simplest store that survives your 12-month scale projection

5. Managed vs. Self-Hosted Decision

FactorManaged (Atlas, DynamoDB, CRDB Cloud)Self-Hosted (Postgres, Qdrant, Cassandra)
Ops burdenNear-zero (patching, failover, backups automated)1–2 engineer-days/month per store
Cost premium30–60% above compute costCompute only
When justifiedTeams < 5 engineers, early stageOps expertise on team, cost-optimized
Lock-in riskHigh (vendor-specific features)Low (self-host anywhere)
ComplianceVendor manages (check SOC2/HIPAA certs)Team manages (more control, more responsibility)

Summary

ConceptRule
5-step eliminationUse the 5-step elimination process; never open a database selection conversation with a product name.
Strong consistencyStrong consistency is required for financial transactions, inventory, and any workflow where two concurrent users must not see conflicting state.
Managed vs. self-hostedManaged cloud services trade 30–60% cost premium for zero ops burden — justified for teams under ~5 engineers; self-host when ops expertise is present.
Interview narrationIn system design interviews, justify the database with the access pattern and scale threshold — not the brand.
Anti-pattern catalogAnti-patterns are architectural debt; Elasticsearch as primary and Redis without AOF are the two highest-frequency production failure patterns in this domain.

What's Next

In Part 8, we ground the entire series in production reality — the canonical failure modes for every paradigm we've covered, with per-database recovery playbooks and GDPR compliance failure modes that appear reliably at scale.
Research & Synthesis Note

This article was developed with AI-assisted deep search, specification cross-referencing, and technical research synthesis.

#Database Selection#System Design#Architecture#System Design Interview#Decision Framework#Cloud Databases
Siddhant Deval

Written by Siddhant Deval

Senior Full-Stack Engineer building high-scale architectures, browser performance engineering systems, and SaaS platforms.