Hiring BarSupport

Cassandra vs DynamoDB

Comparison16 min read3 diagrams

These two are cousins. Both descend from the same family of ideas — consistent hashing, replication across nodes, partition key plus sort order, model your queries before your data — and both are what you reach for when one relational primary can't take the writes. The difference is who carries the pager and how the bill is shaped. Cassandra is software you run: a masterless ring of nodes you size, repair, compact and upgrade, anywhere you like, with consistency you tune per query. DynamoDB is a service you rent: no nodes, no repair, no compaction, AWS only, priced per request or per provisioned unit. The deciding question: are you on AWS and willing to pay per request so nobody ever operates the cluster — or do you need to run it anywhere, or at a steady scale where owning hardware beats renting requests?

The Verdict#

On AWS, default to DynamoDB. Choose Cassandra when you must run outside one cloud, when steady write volume is large enough that nodes are much cheaper than requests and you have the team to run them, or when you need per-query tunable consistency across several self-managed datacenters.

Pick DynamoDB whenPick Cassandra when
You are on AWS and expect to stayYou are multi-cloud, on-prem, or must avoid a single vendor's proprietary API
You have no team to run a distributed database (or don't want one)You have (or will fund) 1–3 engineers who know Cassandra operations
Traffic is spiky, seasonal or unknownTraffic is steady and large: hundreds of thousands of writes/s around the clock
Items are small (≤ 400 KB) and access patterns are key-shapedWide partitions of time-ordered data with TTLs (telemetry, messages, events) at 10s–100s of TB
You want multi-region with a managed replication story (global tables)You want per-query consistency choices (LOCAL_QUORUM here, ONE there) across your own datacenters

🎯 Staff Move: "Both fit the data model, so the decision is operational. We're all-in on AWS and nobody on this team has run a Cassandra repair, so I'll take DynamoDB and pay per request. If this were 500K writes a second, 24/7, for years, I'd price a Cassandra cluster against the DynamoDB bill — but only with a team that's signed up to own it."

Diagram: The Verdict

At a Glance#

DimensionCassandraDynamoDB
Data modelKeyspace → table; partition key + clustering columns; typed columns (CQL)Table; partition key + optional sort key; schemaless items ≤ 400 KB
Query modelCQL: by partition key, ranges over clustering columns; secondary indexes (SAI in 5.0)GetItem, Query within a partition key, Scan; GSIs and LSIs; PartiQL
ConsistencyTunable per request: ONE, QUORUM, LOCAL_QUORUM, ALL; R + W > RF for strong readsStrong or eventual reads on the base table; GSIs eventual
Conflict resolutionLast write wins per cell by timestamp; lightweight transactions (Paxos) for compare-and-setConditional writes per item; transactions up to 100 items; global tables: last writer wins (MREC)
OrderingClustering order within a partitionSort key order within a partition key
Throughput (order of magnitude)~10K–50K writes/s per node, linear with nodes; clusters of 100s of nodes existEffectively unbounded per table; ~1,000 writes/s and 3,000 reads/s per partition (as of 2026)
LatencySingle-digit ms p99 when healthy; GC pauses and compaction cause spikesSingle-digit ms for key operations, consistently
Partition sizeKeep under ~100 MB; larger works but hurts repair and readsNo partition size limit (except 10 GB per item collection with LSIs)
Scaling modelAdd nodes; token ranges stream to them (hours for large nodes)Automatic partition splits; you design keys to spread load
Operational burdenHigh: repair, compaction tuning, tombstones, JVM, upgrades, capacity planningVery low: keys, capacity mode and alarms
Managed optionsAmazon Keyspaces (CQL-compatible, serverless), DataStax Astra, Azure Managed Instance, Instaclustr, othersAWS only
Cost shapeNodes × hours + storage + people; cheap per operation at steady high loadPer request or per provisioned unit + storage; cheap at low or spiky load
Multi-regionNative multi-datacenter replication, per-DC replication factor, active-activeGlobal tables: eventual (any number of regions) or strong (exactly three)

How They Actually Differ#

Who Runs the Ring#

Cassandra is a ring of equal nodes. Each owns token ranges; every write goes to RF replicas chosen by the partition key's token; any node can coordinate any request. There is no leader to fail over — a node down means its replicas take the load and hints queue up for it. In exchange, you own everything a service would hide: node sizing, adding capacity before disks fill, streaming data to new nodes, upgrades one node at a time, JVM tuning, and above all repair.

DynamoDB has the same partitioning idea inside, but you never see a node. Partitions split and move automatically; replication across three availability zones is built in; there is no repair, no compaction, no upgrade window.

Diagram: Who Runs the Ring

Who pays: with Cassandra, a database platform team pays every week in operations. With DynamoDB, the application team pays in modeling constraints and finance pays per request.

Tunable Consistency vs Fixed Choices#

Cassandra lets each request pick its consistency. With RF=3, writing and reading at QUORUM (2 of 3) guarantees overlap, so reads see the latest acknowledged write; ONE is faster and may be stale; LOCAL_QUORUM keeps quorum inside one datacenter so a cross-region link doesn't sit on the request path. This is powerful and easy to misuse — a team writing at ONE and reading at ONE has eventual consistency whether they meant to or not.

DynamoDB offers two read choices on the base table (strong or eventual, strong costing 2× the read units) and no choice on GSIs. Writes are always durable across AZs before acknowledgement. Fewer knobs, fewer ways to be wrong.

NeedCassandraDynamoDB
Read-your-writes in one regionLOCAL_QUORUM writes + LOCAL_QUORUM readsStrongly consistent GetItem / Query
Cheapest possible reads, staleness OKONE / LOCAL_ONEEventually consistent reads (half price)
Compare-and-setLightweight transaction (IF NOT EXISTS, IF col = x): Paxos, ~4 round trips, avoid on hot pathsConditional write: same cost as a normal write
Multi-item atomicityLogged batches (atomic, not isolated) within reasonTransactWriteItems ≤ 100 items, 2× cost

🎯 Staff Insight: Last write wins in Cassandra is decided by client- or coordinator-supplied timestamps. A node with a clock 2 seconds fast silently wins every conflict for 2 seconds. Keep clocks tight and avoid read-modify-write on the same cell from many writers.

Deletes, Tombstones and Repair#

This is the difference that surprises teams moving from DynamoDB to Cassandra. Cassandra never deletes in place; it writes a tombstone that shadows older data until compaction removes both — but only after gc_grace_seconds (10 days by default). Two consequences:

  • Repair is mandatory. If a replica missed a delete and repair doesn't run within gc_grace_seconds, the tombstone is purged elsewhere and the missed replica's old value comes back — "zombie" data. Full or incremental repair on a schedule is a correctness requirement, not hygiene.
  • Tombstone-heavy reads fail. A queue-like table where you insert and delete constantly makes reads scan thousands of tombstones; by default Cassandra warns at 1,000 and aborts the query at 100,000 tombstones per read.

DynamoDB deletes are deletes. TTL expiry runs in the background (typically within a few days of expiry), at no write cost, and there is nothing to repair.

Wide Partitions and Time Series#

Cassandra's storage engine is excellent at append-heavy, time-ordered data: partition by (sensor_id, day), cluster by timestamp, set a table TTL, and use time-window compaction so whole SSTables expire at once. That pattern is how many large telemetry, messaging and event histories are stored. A partition can hold millions of rows (keep it under ~100 MB).

DynamoDB handles the same model — partition key sensor#day, sort key timestamp — with two differences: each partition key value is capped at ~1,000 writes/s, so very hot series need write sharding; and storage cost per GB is higher than raw disk on your own nodes, which matters at hundreds of terabytes of mostly cold data.

The same message-history table in each:

-- Cassandra (CQL)
CREATE TABLE messages (
  channel_id  bigint,
  bucket      int,            -- 10-day time bucket keeps partitions under ~100 MB
  message_id  timeuuid,
  author_id   bigint,
  body        text,
  PRIMARY KEY ((channel_id, bucket), message_id)
) WITH CLUSTERING ORDER BY (message_id DESC)
  AND default_time_to_live = 0
  AND compaction = {'class': 'UnifiedCompactionStrategy'};
-- read: SELECT * FROM messages WHERE channel_id = ? AND bucket = ? LIMIT 50;   (LOCAL_QUORUM)

# DynamoDB
PK = "CH#<channel_id>#<bucket>"     SK = "<message_id as sortable ULID>"
attributes: author_id, body
read: Query PK = "CH#123#2026-40", ScanIndexForward = false, Limit = 50   (strongly consistent)
hot channel (> ~1,000 writes/s): add a shard suffix to PK and merge on read

Same keys, same thinking. What differs is everything around them: on Cassandra you choose the compaction strategy and run repair; on DynamoDB you choose a capacity mode and watch for throttles.


Where Each One Breaks#

Cassandra#

FailureWhat happensDetectionOwner
Repair skippedMissed deletes resurrect after gc_grace_seconds; replicas driftLast successful repair age per tableDB platform
Tombstone overloadQueue-like delete patterns; reads abort at the failure thresholdTombstone warnings in logs, read latencyApp team (data model)
Hot or huge partitionOne partition at 1 GB+ or 10× traffic; its 3 replicas saturate; repair and compaction slowPartition size histograms, per-node load skewApp team
Compaction falls behindPending compactions grow; reads touch more SSTables; disk fillsPending compaction tasks, SSTables per readDB platform
GC pausesMulti-hundred-ms stop-the-world pauses; coordinator timeouts; nodes flapGC pause time, dropped messagesDB platform
Disk full before scalingAdding a node streams data and compaction needs headroom; at 80%+ disk, expansion itself is riskyDisk used % per node (alert at 50–60%)DB platform

DynamoDB#

FailureWhat happensDetectionOwner
Hot partition keyOne key over ~1,000 writes/s throttles while the table looks idleThrottledRequests, Contributor InsightsApp team
GSI lag / throttleGSI can't keep up; reads stale; base writes throttledGSI throttle eventsApp team
Large items400 KB items make every read expensive; attempts to store wide rows hit the limitConsumed capacity per requestApp team
Unplanned access patternA new query needs a Scan or a new GSI and backfillScan usageProduct + app team
Cost at steady high loadOn-demand bill grows linearly with traffic foreverMonthly cost per tableApp team + FinOps
Regional service eventDependent on one provider's region health; no self-help beyond global tablesAWS health events, error ratesPlatform

Zombie Data from a Skipped Repair#

day 0     node C is down for 3 hours during a network incident; hints expire before it returns
day 0     user deletes 40K old messages → tombstones written to A and B only (C missed them)
day 1-14  repair job has been failing silently since a config change two weeks ago
day 10    gc_grace_seconds (10 days) passes; compaction on A and B purges tombstones and data
day 15    read at ONE hits node C → deleted messages returned; read repair copies them back to A and B
day 15    support tickets: "deleted messages are back"
Detection repair-age-per-table alert (should page at > 7 days); tombstone/purge metrics
Fix       restore deletes from audit log; fix the repair schedule; alert on repair failures
Owner     DB platform team (repair), with the app team re-issuing deletes

DynamoDB has no equivalent failure: there is no repair to skip. That absence is a large part of what you pay for.

The production surprise: Cassandra failures are slow and operational (repair debt, compaction backlog, disks filling over weeks). DynamoDB failures are fast and design-level (one hot key, one missing index). Cassandra rewards a team that watches dashboards weekly; DynamoDB rewards a team that reviews data models carefully once.


Cost and Operations#

Cassandra (self-run)DynamoDB
Who runs itA database platform team: capacity, repair, compaction, upgrades, on-callAWS; app team owns keys, capacity mode and alarms
Bill scales withNodes × hours (RF=3 means 3× raw data on disk, plus 30–50% headroom) + peopleWrites, reads and GB stored; GSIs repeat writes; global tables repeat writes per region
Idle costFull cluster 24/7Storage only (on-demand)
People~1–3 engineers for a serious multi-team deploymentNear zero for operations
Where it winsSteady, very high throughput; very large mostly-cold datasets; outside AWSSpiky, small or medium load; teams without database operators
What on-call watchesCassandraDynamoDB
The SLO metricp99 read/write latency per datacenter, dropped mutationsp99 latency, ThrottledRequests
The "act now" alertNode down + another node unhealthy in the same replica set; disk > 60%; repair failingSustained throttling; GSI throttles; cost anomaly
Routine workRepair scheduling, compaction tuning, rolling upgrades, adding nodes ahead of growthKey reviews, capacity mode, backup and TTL settings

Cassandra capacity rules of thumb that interviewers like to hear:

RuleWhy
Keep disk use under ~50–60% per nodeCompaction and streaming for new nodes need free space
~1–2 TB of data per node (more with care)Larger nodes take longer to stream, repair and replace
RF=3 per datacenter, LOCAL_QUORUM for both reads and writesSurvives one node loss per DC with consistent reads
Partitions under ~100 MB, bucket by time if unboundedLarge partitions slow reads, repair and compaction
Add capacity at ~70% of throughput or storage headroomBootstrapping a node adds load before it relieves it

Rough break-even. 200,000 writes/s of 1 KB, steady, 24/7:

DynamoDB on-demand:   200K × 2.59M s ≈ 518B WRU/month × $0.625/M ≈ $324K/month (writes only, us-east-1, as of 2026)
DynamoDB provisioned: same load on provisioned capacity with reserved pricing is a fraction of that —
                      typically several times cheaper than on-demand at steady utilisation
Cassandra:            ~10–20K writes/s per node → 15–30 nodes at RF=3 with headroom, plus 2 engineers;
                      tens of thousands of $/month in instances and storage, plus salaries

At this scale, self-run Cassandra can be several times cheaper than on-demand DynamoDB, and the gap to provisioned-and-reserved DynamoDB is much smaller. At 2,000 writes/s the comparison flips completely: DynamoDB costs a few thousand dollars a month on-demand (much less provisioned) and Cassandra still needs a minimum cluster and a person.

🧭 Principal Insight: "The real comparison isn't Cassandra nodes versus DynamoDB requests — it's DynamoDB requests versus Cassandra nodes plus the two engineers who keep repair running. Below a few hundred thousand dollars a month of DynamoDB spend, those engineers are almost always better spent on the product."


Switching Later#

MoveHowWhat's hard
Cassandra → DynamoDBDual-write from the app, backfill historical data, shadow reads to compare, cut over by traffic percentageItems over 400 KB, wide partitions over ~1,000 writes/s per key, TTL and consistency-level semantics
Cassandra → Amazon KeyspacesCQL-compatible, so the app changes least; data loaded via bulk toolsNot every Cassandra feature or behaviour is supported; check compatibility and quotas first
Cassandra → a Cassandra-compatible engineSame CQL and drivers; migrate data with a migrator toolOperational differences; still self-run or vendor-run
DynamoDB → CassandraExport to S3 or consume Streams; transform; dual-write; cut overRebuilding operations capability from zero; GSIs become denormalised tables
Either → relationalUsually only for a slice that needs joins and transactionsThroughput may exceed one primary

One-way doors: partition key design on either system (a change rewrites every row); Cassandra replication topology across datacenters; DynamoDB global table consistency mode. Two-way doors: DynamoDB capacity mode; Cassandra compaction strategy per table; node instance type.

Diagram: Switching Later

How Real Companies Chose#

Discord: Outgrew Its Cassandra Operations, Stayed on the Data Model#

By 2022 Discord stored trillions of messages on a 177-node Cassandra cluster and described it as a heavy operational burden: hot partitions from busy channels causing cascading latency, JVM garbage-collection pauses, and compaction backlogs that required taking nodes out of rotation. They moved to ScyllaDB — a Cassandra-compatible engine — on 72 nodes, with p99 for historical reads going from 40–125 ms to about 15 ms and inserts from 5–70 ms to a steady 5 ms. They also added Rust data services in front that coalesce concurrent requests for the same data (Discord Blog).

Staff insight: Discord kept the wide-column data model and self-hosting; what they changed was the engine's operational profile. The hot-partition problem they fixed with request coalescing in front of the database — no storage engine removes the need to protect a hot key.

Heroku: Self-Run Cassandra to DynamoDB#

In an AWS-published case study, Heroku describes moving its metrics-as-a-service platform — about 30 TB, hundreds of thousands of observations per second — from self-managed Cassandra on EC2 to DynamoDB. The small database team wanted to stop operating clusters; they ran both paths in parallel, ramping shadow queries to 100% before cutting over, and report p99 spikes of ~80 ms on Cassandra versus consistently under 20 ms on DynamoDB, with operational overhead reduced by up to 90% (AWS Database Blog).

Staff insight: The trigger was team size, not scale. A small team running a distributed database spends its time on the database instead of the product. (It is a vendor-published story; the shape of the decision is the useful part.)

Amazon: The Managed End of the Spectrum#

The 2022 USENIX paper on DynamoDB describes a service designed for predictable performance in a multi-tenant system, with partitions split and moved automatically, and reports a peak of 89.2 million requests per second during Prime Day 2021 (USENIX ATC '22). By Prime Day 2025, AWS reported a peak of 151 million requests per second (AWS News Blog).

Staff insight: The paper's emphasis is predictability, not raw speed — consistent latency while the service rebalances under you. That is the thing you are buying instead of a Cassandra operations team.


Follow-Ups to Expect#

After You Say...They Will Ask...What They're Testing
"Cassandra with RF=3""What consistency level for reads and writes, and why?"R + W > RF, LOCAL_QUORUM, what ONE actually means
"We delete expired messages""What happens to read latency on that table?"Tombstones, TTL with time-window compaction, gc_grace_seconds
"Cassandra for multi-region""Two regions update the same row at once."Last write wins per cell, clock skew, LWT cost
"DynamoDB""One channel gets 20K messages a second."Per-partition limits, write sharding, caching in front
"DynamoDB is cheaper""At what scale does that stop being true?"Pricing model; on-demand vs provisioned vs nodes plus people
"We'll run Cassandra ourselves""Who runs repair, and what happens if it doesn't run for two weeks?"Ownership; zombie data; operational maturity
"Keyspaces gives us both""What's different from open-source Cassandra?"Knowing compatibility layers have gaps
"LOCAL_QUORUM everywhere""A whole region goes down. What do users in it see?"Per-DC replication, client failover to another DC, and what consistency you get after

What to Say in the Interview#

"Cassandra and DynamoDB take the same data model — I'll design partition and sort keys the same way for either. The choice is who operates it and how we pay."

"We're on AWS with no database operations team, so DynamoDB. If this were 200K writes a second, steady, for years, I'd price a Cassandra cluster plus two engineers against provisioned DynamoDB before committing."

"If we do run Cassandra, repair runs on a schedule shorter than gc_grace_seconds and someone is paged when it doesn't — otherwise deleted data comes back."

"Either way, the hottest channel gets request coalescing in front of the database, because no storage engine makes one partition key infinitely fast."


  1. Loading the index…