Study interactive :: Progress tools open in the Study Hub reader.

15. NoSQL

"NoSQL" is a confusing label. It just means "not the traditional relational SQL database". That covers a dozen very different things. Calling MongoDB, Redis, and Cassandra all "NoSQL" is like calling a hammer, a screwdriver, and a chainsaw all "hand tools". Technically true, completely unhelpful.

Let's break it apart by what these databases actually do.

The four flavors

Key-value

The simplest. A giant hash map: key in, value out. Values are opaque blobs the DB doesn't understand.

SET user:42 "{\"name\":\"Ada\",\"plan\":\"pro\"}"
GET user:42
EXPIRE user:42 3600

That's the whole API, basically.

Document

Like key-value, but the value is a structured document (usually JSON). The DB understands the structure and can query inside it.

db.users.insertOne({
  name: "Ada",
  email: "[email protected]",
  preferences: {
    theme: "dark",
    notifications: ["email", "push"]
  },
  posts: [
    { title: "Hello", views: 42 },
    { title: "Day 2", views: 17 }
  ]
});

db.users.find({ "preferences.theme": "dark" });

You can query nested fields directly. Try doing that cleanly in SQL. (You can, with JSONB in Postgres, but it's not as ergonomic.)

Wide-column

Tables, but with flexible columns. Each row can have different columns. Optimized for huge volumes of writes and analytical queries across many rows.

Cassandra's data model:

CREATE TABLE events (
    user_id     UUID,
    event_time  TIMESTAMP,
    event_type  TEXT,
    payload     TEXT,
    PRIMARY KEY (user_id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);

INSERT INTO events (user_id, event_time, event_type, payload)
VALUES (uuid(), now(), 'login', '{"ip":"1.2.3.4"}');

SELECT * FROM events WHERE user_id = ? LIMIT 50;

Note the schema looks SQL-ish. But the engine underneath is completely different: no joins, no transactions in the SQL sense, partitioning baked in.

Graph

Data is nodes and edges. Queries traverse relationships.

Cypher query in Neo4j:

MATCH (me:Person {name: "Ada"})-[:FRIEND*2]-(friend_of_friend)
WHERE NOT (me)-[:FRIEND]-(friend_of_friend)
RETURN friend_of_friend.name
LIMIT 10

"Find friends-of-friends I'm not yet friends with." Try doing that in SQL with multiple joins on a 10-million-row graph. It's painful. In a graph DB it's natural and fast.

Why use NoSQL at all

SQL is great. So why does NoSQL exist? Three reasons usually:

1. Schema flexibility

In SQL, adding a column to a 1-billion-row table is a migration. In a document DB, you just start writing the new field. Old documents don't have it; new ones do; the app handles both.

This sounds great. It's also dangerous. Schema enforcement saves you from yourself. NoSQL pushes that responsibility to the app code, where it's easy to forget.

2. Horizontal scale by default

Postgres can be replicated and sharded, but it takes work. Cassandra and DynamoDB are sharded out of the box. You add nodes, they pick up data. This matters once you're past the single-machine limit.

3. Specific data shapes

If you have a graph, a graph DB is a better fit. If you have time series, a time-series DB is. If you have a giant key-value workload, a KV store is. Trying to fit those into SQL works but isn't always optimal.

What you give up

NoSQL almost always trades something for those gains:

For most apps, SQL gives you all of this and you're fine. Reach for NoSQL when you have a specific reason.

A common middle ground: SQL with JSON

Postgres has the JSONB type. You can store schemaless data inside a SQL row and query it with operators:

CREATE TABLE products (
    id      SERIAL PRIMARY KEY,
    name    TEXT,
    details JSONB
);

INSERT INTO products (name, details)
VALUES ('Phone', '{"brand": "Acme", "specs": {"ram": "8GB"}}');

SELECT * FROM products
WHERE details->>'brand' = 'Acme'
  AND details->'specs'->>'ram' = '8GB';

For many "I want flexibility" cases, this beats reaching for MongoDB. You get ACID, joins, and indexes, plus the schemaless bits where you want them.

When to pick what (rough guide)

You're building... Try
A normal product with user data, orders, content Postgres
A cache or session store Redis
A high-volume event log or metrics store Cassandra or ClickHouse
A content / catalog with flexible fields Postgres with JSONB, or MongoDB
A social graph, recommendations Neo4j or graph extension
Globally distributed key-value at huge scale DynamoDB, Spanner
Anything where you're unsure Start with Postgres

The number of teams who picked MongoDB on day one and regretted it is large. The number who picked Postgres and regretted it is small. Bias toward the boring answer.

A real example

Imagine you're building a fitness tracker.

That's a polyglot architecture. Most real systems are. The trick is not picking one DB to rule them all, it's picking the right one for each shape of data.

Things to remember

Going deeper