Blueprint
Fundamentals

SQL vs NoSQL

Every design has a choose-your-database moment, and interviewers aren't scoring the choice — they're scoring whether it was derived from access patterns or from tribe membership.

01

What it is

Relational databases (Postgres, MySQL) store structured rows with enforced schemas, joins, and ACID transactions. NoSQL is an umbrella over four quite different families — key-value (Redis, DynamoDB), document (MongoDB), wide-column (Cassandra), graph (Neo4j) — that generally trade relational guarantees for flexible schemas and native horizontal scale.

The interview reality: both scale, and blanket statements about which is "better" are an instant credibility hit. The scoring is on reasoned selection tied to access patterns — what are the queries, what are the write rates, what needs a transaction — plus knowing the honest default: under roughly 100 GB and 1k QPS, anything works, so pick Postgres and spend the interview on harder problems.

Say this out loud

I'd start with Postgres — the data is relational, bookings need transactions, and the scale doesn't threaten one box — and I'd switch this one write-heavy table to Cassandra only if the math ever pushes past what a leader with replicas can take.

02

The picture

relational — postgres id · name · city_id FK → cities.id · ACID document — dynamo / mongo { user, city, orders: [...] } { user, ... } { user, city, prefs: {...} } partition by key · joins are your job
left: rows that join, constrain and transact. right: self-contained documents that partition and replicate without asking permission. pick per access pattern, not per fashion.
03

The variants and when to pick each

Pick SQL when correctness is the product

Payments, bookings, inventory — anywhere two operations must succeed or fail together — want ACID transactions, and relational databases give them natively. Add complex ad-hoc queries, joins across naturally relational data, and schemas that are stable and worth enforcing, and SQL is the default, not the fallback.

Modern Postgres also scales far beyond the meme: read replicas, table partitioning, and Citus-style sharding extensions carry it to tens of TB and tens of thousands of TPS. The strongest interview posture is Postgres-first with a named escape hatch, not NoSQL-because-scale.

Trade-offStrong guarantees and query flexibility, at the cost of harder horizontal write scaling — when one leader can't take the writes, sharding SQL is manual surgery.

Pick NoSQL when the access pattern is simple and the scale is not

NoSQL earns its place when access patterns are known and key-shaped (get session by ID, get feed items by user), when write throughput demands native sharding, when the schema is genuinely fluid, or when you want multi-region active-active out of the box (Cassandra, DynamoDB global tables).

Match the family to the job: key-value for sessions and carts; document for catalogues and profiles that read as one blob; wide-column for time-series, feeds and write-heavy logs — Cassandra's LSM storage scales writes linearly across the cluster; graph for social edges and fraud rings where the query is the traversal.

Trade-offNative scale-out and schema freedom, in exchange for designing tables around queries you must know upfront — flexibility of storage, rigidity of access.

ACID vs BASE — what you actually give up

ACID: atomic, consistent, isolated, durable — the transaction either fully happens or didn't. BASE: basically available, soft state, eventually consistent — the system stays up and converges later. Most NoSQL stores give atomicity per key or per partition only; multi-item transactions are limited or expensive (DynamoDB transactions exist and cost double the capacity units).

The hidden bill is in the modelling: no joins means denormalising, and denormalised copies mean update anomalies you now own in application code. Secondary indexes are weaker, and eventual consistency is the default read unless you pay for stronger.

Trade-offBASE buys availability and scale by handing consistency responsibilities to the application — every denormalised copy is a bug you haven't written yet.

The decision procedure that scores points

List the top three queries and their rates, and the writes per second at peak. If the maths fits one Postgres node — tens of TB, ~5–10k writes/s comfortable — take Postgres, add replicas for reads, and say what would change your mind. That escape hatch ("if writes pass 10k/s I move this table to Cassandra") is worth more than the choice itself.

If you do pick NoSQL, immediately name the partition key and the query you can no longer do — a DynamoDB table without its access patterns designed upfront is the classic self-inflicted wound. Polyglot is normal at scale: Postgres for orders, Redis for sessions, Cassandra for the event stream — one sentence each, tied to the pattern.

Trade-offChoosing per-workload beats choosing per-ideology, but every extra store is another system to operate, back up, and keep consistent with the others.
04

Numbers worth memorising

Single Postgres nodetens of TB; ~50k simple TPS ceiling, 5–10k writes/s comfortable
DynamoDB per-partition limits1,000 WCU / 3,000 RCU per second, hard
DynamoDB item / Mongo document cap400 KB / 16 MB
Cassandra writeslinear scaling — 10k to 1M+ writes/s across a cluster
The it-doesn't-matter zone<~100 GB and <~1k QPS — anything works, pick Postgres
05

Where the interviewer pushes

The push after a NoSQL pick is "what's your partition key, and what query can you now not do?" The strong answer has both halves ready: partition on user_id so all user-scoped reads are one-partition and fast, and in exchange I've lost cheap global queries — "top items across all users" now needs a scatter, a stream into an aggregate table, or a separate analytics path. Volunteering the sacrificed query before being asked is exactly the signal the question exists to find.

The push after a SQL pick is "would Postgres actually fail here? Show me the math." So do the math out loud: 20M writes/day is ~230/s average, maybe 1k/s peak — one node laughs at that; storage at 1 KB per row is 20 GB/day, so partitioning and archival matter before sharding does. If the numbers genuinely exceed one box, say which table breaks first and move only that one — the answer "Postgres, plus a named migration trigger" beats both tribal answers.

Shows up in

Found a bug or want more?

Tell me what's broken, missing, or wrong. Every message lands in my inbox.