15. When to use Cassandra — and when not to
Cassandra · 15. When to use Cassandra — and when not toCassandra is a specialist. It is superb at a narrow set of problems and actively bad at most others — and unlike a relational database, which degrades gracefully when misused, Cassandra fails months later in a way that requires a migration to fix.
So this chapter is more important here than it was in the PostgreSQL guide.
What Cassandra is genuinely excellent at
Section titled “What Cassandra is genuinely excellent at”Write throughput that scales linearly. The write path is an append to a log and an insert into a sorted memtable — no read, no seek, no lock, no index maintenance. Double the nodes, roughly double the write capacity. There is no coordinator to saturate and no primary to bottleneck.
Surviving the loss of anything. No leader means no failover. A node dies and the cluster does not notice. A whole region dies and the others keep serving at full speed with no promotion, no fencing, and no split brain. This is not a feature bolted on — it is the architecture.
Multi-region active-active. Multiple data centres, each accepting local writes at local latency, replicating asynchronously, resolving conflicts deterministically. Very few systems do this well, and none do it this simply.
Time-series and event data. Append-only, keyed by a known partition, queried over a clustering range, expired by TTL. With TWCS, expiry costs nothing — whole files are deleted. This is the workload Cassandra fits like a glove.
Predictable, boring operations at scale. Rolling upgrades with no downtime. Adding capacity means adding nodes. There is no resharding project, no failover runbook, no primary election to reason about. Clusters of hundreds of nodes and petabytes are routine.
This is also why Cassandra sits unusually well on Kubernetes, via K8ssandra. A platform whose core assumption is that any node may be killed and replaced at any moment is a poor match for a database with a single writable primary — and a very good match for one designed on the premise that no node matters.
Uniform performance regardless of data size. A read touches a bounded number of SSTables whether the table holds a gigabyte or a petabyte. Latency does not degrade as you grow.
The workloads it fits
Section titled “The workloads it fits”Concretely, so you can recognise your own system:
- Metrics, sensors, IoT telemetry. High-volume append, keyed by device, queried by time range, TTL’d.
- Event and activity streams. User activity, audit logs, clickstream.
- Messaging. Messages by conversation, ordered by time — the shape Cassandra was originally written for.
- Product and session catalogues keyed by a known ID with very high read and write volume.
- Anything global and always-on. Systems where a regional outage must be invisible.
- Write-mostly workloads that flattened a relational primary and where the access patterns are genuinely few and known.
- Append-only event logs that other systems are built on. Temporal stores every workflow’s event history in Cassandra for exactly this reason — keyed writes, no ad-hoc querying, and a write rate proportional to how much work the cluster is doing.
The common thread: a small number of well-known access patterns, always by a specific key, at a volume or availability requirement that one machine cannot meet.
Where you should use something else
Section titled “Where you should use something else”1. You do not know your queries yet
Section titled “1. You do not know your queries yet”If your product is early and the access patterns are still changing weekly, Cassandra is the wrong choice — and this is the most common mistake.
A relational database lets you add an index and answer a new question this afternoon. Cassandra requires a new table, a backfill of all historical data, and a change to every writer. A query the model did not anticipate is not slow; it is impossible.
Use PostgreSQL until the access patterns are stable and one machine is genuinely the limit. Migrating later is real work, but it is far less work than fighting a data model you designed before you knew what you needed.
2. You need transactions
Section titled “2. You need transactions”No BEGIN. No rollback. No multi-row atomicity. No foreign keys. No isolation.
LWTs give compare-and-set on a single partition at ten to twenty times the cost of a normal write, and they degrade badly under contention (chapter 11). Batches are not transactions.
Anything with a financial ledger, an inventory count that must be exact, a booking that must not double-book, or an invariant spanning multiple rows belongs in a database with transactions. PostgreSQL, or CockroachDB / YugabyteDB if you also need horizontal scale.
3. You need ad-hoc queries and analytics
Section titled “3. You need ad-hoc queries and analytics”There are no joins. Aggregates only make sense within a partition. ALLOW FILTERING is a full cluster scan.
Your analysts cannot query Cassandra. Your BI tool cannot query Cassandra. SELECT count(*) on a large table will time out.
The standard answer is to keep Cassandra as the operational store and export to something else — Spark for batch, or a columnar warehouse (ClickHouse, BigQuery, Snowflake) for analysis. That is a legitimate architecture, and it is also a second system with a synchronisation problem. Factor it into the decision.
4. Your data is small
Section titled “4. Your data is small”Cassandra’s overheads only pay off at scale. Below roughly a terabyte, or below a few tens of thousands of writes per second, a single well-tuned PostgreSQL server will outperform a three-node Cassandra cluster on almost every dimension — latency, flexibility, operational effort, and cost.
A three-node minimum cluster, JVM tuning, repair scheduling, compaction strategy per table, and a data model you cannot change later is a great deal of machinery to run a 200 GB dataset. If you are not clearly past what one machine can do, you are paying Cassandra’s costs without receiving its benefits.
5. You need strong consistency everywhere
Section titled “5. You need strong consistency everywhere”LOCAL_QUORUM gives you read-your-writes within a data centre. Across data centres, replication is asynchronous and reads can be stale.
If your application genuinely requires linearizable, globally consistent reads on every operation, Cassandra will fight you the whole way. EACH_QUORUM gets you there and simultaneously destroys the availability you chose Cassandra for.
CockroachDB, YugabyteDB, or Spanner are built for globally consistent distributed SQL. They are slower per operation and they will not accept writes during a partition — which is precisely the trade Cassandra refuses to make.
6. Queues, and anything delete-heavy
Section titled “6. Queues, and anything delete-heavy”Chapter 7 and chapter 14 both cover this because it matters that much. Deletes write data. Reads merge tombstones. A workload dominated by deletes degrades until it fails.
Queues: Kafka, SQS, RabbitMQ, Pulsar. Anything with churn where rows are created and destroyed constantly: a relational database, or Redis.
Cassandra versus the alternatives
Section titled “Cassandra versus the alternatives”| Cassandra | PostgreSQL | MongoDB | DynamoDB | ScyllaDB | |
|---|---|---|---|---|---|
| Write scaling | linear, no ceiling | one node | sharded | managed, elastic | linear |
| Multi-region writes | native, active-active | no | limited | global tables | native |
| Transactions | single-partition CAS | full ACID | multi-doc ACID | limited | single-partition CAS |
| Ad-hoc queries | no | yes | yes | no | no |
| Joins | no | yes | limited | no | no |
| Ops burden | high | moderate | moderate | none (managed) | lower than Cassandra |
| Cost at scale | hardware | hardware | hardware | can be very high | hardware |
ScyllaDB deserves particular attention if you have already decided on Cassandra’s model. It is a C++ reimplementation, wire-compatible with Cassandra, with a shard-per-core architecture and no JVM. In practice it delivers substantially better throughput per node, far more predictable latency (no GC pauses), and self-tuning behaviour that removes much of chapter 13. The trade is a smaller community and a commercial company at the centre. If you are choosing today and the Cassandra data model fits, Scylla deserves a serious evaluation.
DynamoDB is worth naming for a different reason. It is the same Dynamo lineage, fully managed, with zero operational burden — no repair, no compaction tuning, no JVM, no nodes. If you are on AWS and your workload fits, it removes an enormous amount of work. The costs are vendor lock-in and a pricing model that can become brutal at high sustained throughput.
The honest limits, stated plainly
Section titled “The honest limits, stated plainly”Even where Cassandra is the right choice:
The data model is close to permanent. You cannot change a primary key. Getting it wrong means a new table and a full migration, and you usually find out at scale.
Repair is a permanent operational duty. Weekly, on every table, forever. Skipping it resurrects deleted data.
Compaction must be tuned per table and monitored continuously.
The JVM is part of your job. Heap sizing, garbage collection, and pause analysis. (Unless you use Scylla.)
No ad-hoc queries, ever. Every question needs a table designed in advance.
Minimum viable cluster is three nodes, realistically more, per data centre.
Deletes are expensive and dangerous. The tombstone model shapes what workloads are viable.
Clock synchronisation is a correctness requirement, not an operational nicety.
The decision, honestly
Section titled “The decision, honestly”Cassandra is the right answer when you can say yes to most of these:
□ Write volume genuinely exceeds what one machine can absorb, or will within a year□ The access patterns are few, known, and stable□ Every query has a natural partition key□ Availability requirements are strict — a region must be able to disappear without an outage□ Eventual consistency across regions is acceptable□ Data is append-heavy; deletes are rare or handled by TTL□ You have — or will hire — people who will own repair, compaction, and the JVM□ The dataset is large enough (multi-terabyte) to justify all of itIf you are unsure about more than two of those, use PostgreSQL and revisit the question when you have a measured problem. Migrating to Cassandra later is real work; building on the wrong data model for two years is worse.
And the inverse is worth stating too: when Cassandra fits, nothing else fits as well. A globally distributed, always-available, linearly-scaling write store with predictable latency at petabyte scale is a genuinely hard thing to build, and Cassandra has been doing it in production for fifteen years.
What to take from this chapter
Section titled “What to take from this chapter”- Excellent at: linear write scaling, surviving anything, multi-region active-active, time-series, and predictable operations at petabyte scale.
- Wrong for: unknown queries, transactions, analytics, small datasets, globally strong consistency, and queues.
- The most common mistake is adopting it too early, before the access patterns are stable.
- Evaluate ScyllaDB if the model fits — same interface, no JVM, better throughput. Evaluate DynamoDB if you are on AWS and want the operations to disappear.
- Its hard limits: an unchangeable data model, mandatory repair, per-table compaction tuning, the JVM, and no ad-hoc queries.
- If you cannot confidently tick most of the checklist, use PostgreSQL and wait for a measured problem.
One chapter left: the reference card.