Databases

NoSQL Databases

● Beginner ⏱ 11 min read database

NoSQL databases emerged to solve problems that relational databases handle poorly: extremely high write throughput, flexible schemas that evolve without migrations, and horizontal scaling across many cheap commodity servers. Understanding the different NoSQL families — document, key-value, wide-column, graph — and what each one actually optimizes for prevents the mistake of reaching for “NoSQL” as a generic solution to a problem that may not need it.

What Is NoSQL?

NoSQL (Not Only SQL) is a broad term for databases that do not use the traditional relational table model. The defining characteristics are:

💡
NoSQL Is Not One Thing

Document databases (MongoDB), key-value stores (Redis), wide-column stores (Cassandra), and graph databases (Neo4j) are all called “NoSQL,” but they have almost nothing in common beyond rejecting the relational model. Each is designed for a fundamentally different use case. Saying “we use NoSQL” tells you almost nothing about the system; saying “we use Cassandra for time-series writes and Redis for session caching” tells you everything.

Document Databases

Document databases store data as semi-structured documents — typically JSON or BSON. Each document is self-contained: the data and its metadata live together. Documents in the same collection can have different shapes; there is no enforced schema at the database level.

How They Work

Instead of rows in tables, you have documents in collections. A user document might contain their name, email, preferences, and an embedded array of addresses — all in a single document. When you fetch the user, you get everything without a join. When you update the user’s email, you update one document.

Documents are indexed by a primary key (typically _id). Secondary indexes can be created on any field, including fields inside nested objects and arrays. Queries look like { "country": "US", "age": { "$gte": 18 } } rather than SQL.

Strengths

Weaknesses

Examples

MongoDB — the most widely deployed document database. BSON storage, rich query language, aggregation pipeline, Atlas managed service. Couchbase — document store with built-in caching and N1QL (SQL-like query language). Firestore — Google’s serverless document database, popular for mobile and web apps. Amazon DocumentDB — MongoDB-compatible managed service on AWS.

Best for: Content management, product catalogs, user profiles, event data, mobile app backends where the schema evolves frequently.

Key-Value Stores

The simplest data model: every piece of data is a value identified by a unique key. The database has no knowledge of the value’s structure — it’s an opaque blob. Operations are: GET, SET, DELETE. Some stores add TTL (time-to-live) for automatic expiry, atomic counters, and pub/sub.

How They Work

Data is stored in a hash table (in-memory stores like Redis) or an LSM-tree (disk-backed stores like RocksDB). Lookups are O(1) by key. There is no query language — you cannot ask “give me all keys where value.age > 18.” You must know the key to retrieve the value.

Redis in Depth

Redis is more than a simple key-value store. It supports rich data structures — strings, lists, sorted sets, hashes, bitmaps, HyperLogLogs, streams — each with dedicated atomic operations. This makes it extremely versatile:

Examples

Redis — in-memory, supports persistence via AOF/RDB snapshots, cluster mode for horizontal scaling. Memcached — simpler in-memory cache, multi-threaded, no persistence. DynamoDB — AWS-managed, supports key-value and document models, single-digit millisecond latency at any scale. etcd — distributed key-value store designed for configuration and service discovery (powers Kubernetes).

Best for: Session storage, caching database queries, real-time counters, rate limiting, distributed coordination.

Wide-Column Stores

Wide-column stores organize data into rows with a key, but each row can have a different set of columns, and columns are grouped into column families. Unlike document databases, wide-column stores are designed for extreme write throughput and massive datasets distributed across many nodes with no single point of failure.

How They Work

In Cassandra, you design your data model around your query patterns — not your data relationships. You create a table whose partition key determines which node stores the data, and whose clustering key determines the sort order within that partition. Writes go to the node(s) responsible for that partition key; reads go to the same node(s). This enables linear horizontal scalability: double the nodes, roughly double the throughput.

Under the hood, Cassandra uses an LSM-tree storage engine. Writes go to an in-memory structure (memtable) and a commit log. The memtable is periodically flushed to disk as immutable SSTables. Reads may need to merge data from the memtable and multiple SSTables, plus tombstones for deleted data — making reads more expensive than writes in write-heavy LSM systems.

Strengths

Weaknesses

Examples

Apache Cassandra — open-source, widely deployed at Netflix, Apple, Discord. Amazon Keyspaces — managed Cassandra-compatible service. HBase — Hadoop ecosystem wide-column store. Google Bigtable — the original wide-column store, powering Gmail, Google Search indexing, and many Google services.

Best for: IoT sensor data, time-series metrics, activity feeds, audit logs — any workload with very high write rates and known, narrow query patterns.

Graph Databases

Graph databases store data as nodes (entities) and edges (relationships). Each node and edge can carry properties. The database is optimized for traversing relationships — following edges from node to node — which is extremely slow in a relational database with deep joins.

How They Work

In a relational database, finding all friends-of-friends requires a JOIN on the friends table with itself. With 5 degrees of separation and millions of users, this becomes a recursive join over a massive table — impractically slow. In a graph database, following edges is a O(1) pointer dereference per hop, regardless of total graph size. The graph is stored as adjacency lists optimized for traversal.

Queries use graph-specific languages. Cypher (Neo4j) expresses graph patterns declaratively:

MATCH (u:User {name: "Alice"})-[:FRIEND*2]->(fof:User)
WHERE NOT (u)-[:FRIEND]->(fof)
RETURN fof.name

Examples

Neo4j — the dominant graph database, native graph storage, Cypher query language. Amazon Neptune — managed graph database, supports both property graph (Gremlin) and RDF (SPARQL). JanusGraph — distributed graph database backed by Cassandra or HBase.

Best for: Social networks (friend recommendations), fraud detection (connected account rings), knowledge graphs, recommendation engines, identity and access management graphs.

Eventual Consistency

Most NoSQL databases sacrifice strong consistency for availability and partition tolerance (the CAP theorem trade-off). In an eventually consistent system, a write on one node is not immediately visible on other nodes — it propagates asynchronously. Given enough time without new writes, all nodes will converge to the same value.

This has real consequences:

Many NoSQL databases offer tunable consistency. Cassandra lets you set the consistency level per query: reading from a QUORUM of replicas gives stronger guarantees than reading from ONE. DynamoDB offers strongly consistent reads at extra cost. MongoDB offers configurable write concerns and read concerns.

⚠️
Eventual Consistency Is Not “Fine for Most Cases”

Eventual consistency is correct for some use cases (activity feeds, view counts, analytics) and catastrophically wrong for others (financial balances, inventory, authentication tokens). The mistake is assuming eventual consistency is “good enough” for a use case without carefully analyzing what happens when reads return stale data. Think through: what is the worst-case impact if a user sees a value that is 500ms or 10 seconds out of date?

When to Use NoSQL

Each NoSQL type has a clear sweet spot. Use NoSQL when a specific, genuine constraint makes SQL the wrong fit:

Use CaseRecommended TypeWhy
Caching, sessions, rate limitingKey-Value (Redis)Sub-millisecond latency, TTL, atomic ops
Variable-schema content, catalogsDocument (MongoDB)Schema flexibility, embedded documents
High-volume time-series / IoT writesWide-Column (Cassandra)Linear write scalability, partition-aware storage
Social graphs, recommendationsGraph (Neo4j)Efficient multi-hop traversal
Full-text searchSearch Engine (Elasticsearch)Inverted index, relevance ranking
Metrics and monitoringTime-Series (InfluxDB, Prometheus)Optimized compression and time-window aggregations
Start SQL, Add NoSQL Precisely

The pattern that works at scale is: relational database for core transactional data, one or two NoSQL stores added for specific performance requirements. Every NoSQL system you add is another thing to monitor, backup, tune, and on-call for. Add Redis when your cache hit rate analysis shows you need sub-millisecond lookups. Add Cassandra when your write throughput analysis shows a single PostgreSQL primary is the bottleneck. Don’t add NoSQL because you think you might need scale someday.