SQL vs NoSQL
Structured, relational, ACID-guaranteed tables against flexible-schema document and key-value stores — and how to actually choose.
3 min read
"NoSQL" isn't one technology — it's an umbrella term for databases that don't use the relational table model this course has covered, including document stores (MongoDB), key-value stores (Redis, DynamoDB), wide-column stores (Cassandra), and graph databases (Neo4j). The comparison that matters in practice is less "SQL vs. NoSQL" as a single axis, and more a handful of concrete trade-offs.
Schema: enforced upfront vs. flexible
A relational database enforces its schema on every write, as covered throughout this course — a column's type and constraints are checked before a row is ever accepted. A document database like MongoDB stores flexible JSON-like documents, and different documents in the same collection can have entirely different fields:
-- SQL: every row in `users` has exactly these columns, guaranteed
INSERT INTO users (name, email) VALUES ('Ada', 'ada@example.com');// MongoDB: each document's shape is independent
db.users.insertOne({ name: "Ada", email: "ada@example.com" });
db.users.insertOne({ name: "Grace", email: "grace@example.com", betaFeatures: ["dark_mode"] });This is a genuine trade-off, not a strict upgrade in either direction: a flexible schema is faster to iterate on early in a project, when the shape of your data is still changing — but it pushes the responsibility for consistency onto application code, since the database itself no longer guarantees every document has the fields you expect.
Relationships: joins vs. denormalized documents
Relational databases are built around splitting data across tables and reconnecting it with JOIN, as this entire course has covered — which keeps data from being duplicated, at the cost of a join at query time. Document databases generally favor embedding related data directly inside a document instead:
// Common MongoDB pattern: embed the related data, avoid a "join"
{
name: "Ada",
orders: [
{ product: "Widget", total: 42.00 },
{ product: "Gadget", total: 15.50 },
]
}This avoids a join at read time — fetching a user and their orders is one query, not two combined — but reintroduces the duplication problem normalization solves: the same data can end up repeated across documents, and MongoDB has no built-in mechanism to enforce that repeated copies stay consistent the way a foreign key does.
Consistency guarantees
Relational databases give you the ACID guarantees from the previous lesson by default. Many NoSQL databases historically favored eventual consistency instead, particularly ones built for distributing data across many servers — a write might not be immediately visible to every subsequent read, in exchange for higher availability and throughput at scale. Modern NoSQL databases have narrowed this gap considerably (MongoDB supports multi-document ACID transactions, for instance), but relational databases remain the more predictable default for data where correctness under concurrent writes is non-negotiable — financial records, inventory counts, anything where a stale or inconsistent read is a real problem.
How to actually choose
Reach for a relational database when your data has clear structure and relationships, and correctness (no double-booked reservation, no order placed against an out-of-stock item) matters more than raw write throughput — which describes most application backends. Reach for a NoSQL store for specific, narrower needs it's genuinely better suited to: a key-value store like Redis for a cache or session store, a document database for content with a genuinely variable, evolving shape, or a system that needs to scale writes horizontally across many servers beyond what a single relational database instance can handle. Plenty of real systems use both side by side — a relational database as the system of record, with a specialized NoSQL store layered in for the one workload it fits better.