SQL and NoSQL
The question is asked as a binary and is not one. “NoSQL” names four unrelated data models whose only shared property is not being relational, and the useful answer starts by refusing the framing: what is the access pattern, what invariants must hold, and what shape is the data?
The four families are not interchangeable
| Family | Optimised for | Example |
|---|---|---|
| Key-value | lookup by key | Redis, DynamoDB |
| Document | whole-aggregate read/write | MongoDB |
| Wide-column | huge write volume, known queries | Cassandra |
| Graph | traversal and path queries | Neo4j |
Grouping these as “NoSQL” is like grouping “not-a-hammer”. A key-value store and a graph database have nothing in common except the absence of tables, and choosing between them is a completely different conversation from choosing between either and Postgres.
Relational is the default, and here is why
Not tradition — the query you have not thought of yet.
-- Nobody designed for this. It works anyway.
SELECT c.region, count(*), avg(o.total)
FROM orders o JOIN customers c ON c.id = o.customer_id
WHERE o.created_at > now() - interval '30 days'
GROUP BY c.region;In a document store, that query requires either an aggregation pipeline over a shape that was not designed for it, a second denormalised collection kept in sync, or an export to something else. The relational model’s real product is ad-hoc queryability, and you spend it the moment you denormalise.
The second reason is invariants:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- both, or neitherACID is what lets you say “this cannot happen” rather than “we reconcile nightly”.
What ACID and BASE actually claim
| ACID | BASE | |
|---|---|---|
| A | atomic: all or nothing | basically available |
| C | constraints hold at commit | soft state |
| I | concurrent txns don’t interleave | eventually consistent |
| D | committed survives a crash | — |
Gotcha: “NoSQL means no ACID” is a 2015 claim and interviewers notice. As of 2026, MongoDB has had multi-document ACID transactions since 4.0 and DynamoDB has
TransactWriteItems. The honest statement is that distributed transactions are available but expensive, and the systems are designed so that you avoid needing them.
The C in ACID and the C in CAP are also different things — constraint
validity versus replica agreement. Conflating them is a common slip; see
CAP, ACID, BASE, PACELC.
When a document store genuinely wins
Three conditions, and you want all three:
- The aggregate is read and written whole — a product with its variants, a form with its answers.
- The shape varies per record in ways a table would model as forty nullable columns.
- You do not need to query across documents.
// One read, no joins — this is the win.
db.orders.findOne({_id: id})
// { _id, customer: {...}, lines: [...], payments: [...] }Storing a relational model in documents and then joining in application code is the common mistake. You have taken on the denormalisation cost and kept none of the benefit.
Scaling, honestly
NoSQL scales writes horizontally more easily. That is real, and it is also the answer to a problem most systems do not have: a single Postgres instance in 2026 handles far more than people assume, and read replicas plus partitioning extend it a long way further.
The trade you make when you shard is permanent — no cross-shard joins, no cross-shard transactions without cost, and a partition key you cannot change without a migration. Exhaust vertical and read-replica scaling first, because that decision is reversible and sharding is not.
Polyglot persistence
The realistic production answer is several stores:
- Postgres as the system of record.
- Redis for cache and sessions.
- Elasticsearch or OpenSearch for text search.
- Object storage for blobs.
The cost is operational surface and consistency between them — every copy is a thing that can go stale, and CDC or an outbox is how you keep it honest. See Message queues.
Related
Interview angle 6
- “SQL or NoSQL?” - the wrong framing. Ask about the access pattern, the consistency requirement and the shape of the data. Relational is the safe default because ad-hoc queries and joins stay possible; NoSQL wins when you know the access pattern up front and need its specific scaling model.
- “What are the four NoSQL families?” - key-value for lookup by key, document for self-contained aggregates, wide-column for very high write throughput with known query patterns, and graph for traversal. They have nothing in common except not being relational.
- “When is a document store genuinely better?” - when the aggregate is read and written whole, the schema varies per record, and you don’t need cross-document queries. Storing a relational model in documents and joining in application code takes the cost and none of the benefit.
- “Does NoSQL still mean no ACID?” - no, and saying so dates you. MongoDB has had multi-document transactions since 4.0 and DynamoDB has transactional writes. They are expensive, and the systems are designed so you rarely need them.
- “What does schema-on-read actually cost?” - the schema still exists, it just lives in application code and is no longer enforced. Old documents in old shapes accumulate, and every reader must handle every historical variant.
- “Does NoSQL scale better?” - it scales writes horizontally more easily, at the cost of joins, transactions and query flexibility. Modern Postgres with read replicas and partitioning handles far more than people assume, and sharding is the one decision you cannot undo cheaply.