Amazon DynamoDB and Apache Cassandra are both distributed NoSQL databases that
partition data by key and scale horizontally, and they share a common ancestor in
Amazon's 2007 Dynamo paper. But they sit at opposite ends of the operational
spectrum: DynamoDB is a fully managed, serverless AWS service, while Cassandra is
open-source software you deploy and run yourself as a masterless peer-to-peer ring.
Is DynamoDB or Cassandra the right choice?
Both are horizontally scalable NoSQL stores that partition by key. Choose
DynamoDB if you want a fully managed, serverless database on AWS with no cluster
to operate and pay-per-use billing. Choose Cassandra if you want an open-source,
self-managed, masterless ring — running on your own hardware or across clouds — with
per-query tunable consistency and no vendor lock-in.
DynamoDB vs Cassandra at a glance
| Characteristic | DynamoDB | Apache Cassandra |
|---|---|---|
| Data model | Key-value and document; schemaless JSON-like items | Partitioned wide-column store; rows grouped into partitions |
| Query language | Low-level API operations plus PartiQL (a SQL-compatible query language) | CQL (Cassandra Query Language), an SQL-like language |
| Partitioning / keys | Partition (hash) key, with an optional sort key for a composite primary key | Primary key = one or more partition-key columns plus zero or more clustering columns |
| Secondary indexes | Global secondary indexes (GSI) and local secondary indexes (LSI) | Local secondary indexes (2i) and storage-attached indexing (SAI); materialized views |
| Consistency | Eventually consistent by default; strongly consistent reads available per request | Tunable per operation (e.g. ONE, QUORUM, ALL) against a per-keyspace replication factor |
| Scaling / operations | Fully managed and serverless; AWS handles storage, scaling, patching, and repair | Self-managed masterless ring you deploy on commodity hardware (or a managed Cassandra-compatible service) |
| Multi-region | Global Tables — multi-Region, active-active replication | Multi-datacenter replication configured per keyspace |
| Pricing / ops model | Pay-per-use: on-demand (per request) or provisioned capacity; no infrastructure to run | Free, open-source software (Apache License 2.0); you provision, run, and pay for the infrastructure |
| Best fit | Teams on AWS wanting zero-ops NoSQL that scales automatically | Teams wanting an open-source, self-hosted, cloud-agnostic ring with per-query consistency control |
When DynamoDB is the better choice
- You want zero operational overhead. DynamoDB is fully managed and serverless — there is no cluster to size, patch, repair, or rebalance. AWS handles storage and scaling in the background.
- You are already on AWS. It integrates natively with IAM, Lambda, and the rest of the AWS ecosystem, and Global Tables give active-active multi-Region replication without you standing up datacenters.
- Your traffic is spiky or unpredictable. On-demand capacity bills per request, so you pay for what you use instead of provisioning and running idle nodes.
- You want managed durability and backups. Point-in-time recovery, on-demand backups, and cross-Region replication are configuration, not infrastructure you run.
When Cassandra is the better choice
- You need an open-source, cloud-agnostic database. Cassandra is Apache-licensed and runs anywhere — on-premises, across multiple clouds, or hybrid — with no vendor lock-in to a single provider's managed service.
- You want fine-grained, per-operation consistency control. Its tunable consistency lets each read and write choose a level (such as ONE, QUORUM, or ALL) against the keyspace replication factor, trading latency for consistency per query.
- You want a masterless architecture with no single point of failure. Every node is equal and can serve reads and writes, and the cluster stays available even when individual nodes or whole datacenters go offline.
- You are willing to operate the cluster (or pay a managed provider to) in exchange for that control and portability.
What a CQL query becomes in DynamoDB
CQL looks close enough to SQL that the port feels mechanical. Here is a real
tenant-scoped event log and the query you would run against it:
CREATE TABLE app.tenant_order_events (
tenant_id text,
event_time timestamp,
event_id timeuuid,
order_id text,
status text,
amount decimal,
PRIMARY KEY ((tenant_id), event_time, event_id)
) WITH CLUSTERING ORDER BY (event_time DESC, event_id ASC);
SELECT order_id, status, amount
FROM app.tenant_order_events
WHERE tenant_id = 'acme'
AND event_time >= '2026-07-01 00:00:00+0000'
AND event_time < '2026-08-01 00:00:00+0000'
AND status = 'failed'
LIMIT 100
ALLOW FILTERING;
Three things in that statement land differently.
Two clustering columns, one sort key. PRIMARY KEY ((tenant_id), event_time, event_id)
sorts rows inside the partition by two columns. DynamoDB gives you exactly one sort
key, so both collapse into a single string you concatenate on write
(2026-07-14T09:12:03Z#7c9a…) and parse back on read. The
CLUSTERING ORDER BY … DESC that Cassandra fixes at table creation becomes
ScanIndexForward: false, set per request.
ALLOW FILTERING becomes silent. Cassandra rejects that statement without the
clause, and the CQL spec warns that a query using it "may thus have unpredictable
performance". DynamoDB asks for no opt-in. status moves into a FilterExpression
and the request looks like any other:
{
"TableName": "tenant_order_events",
"KeyConditionExpression": "tenant_id = :t AND event_sk BETWEEN :from AND :to",
"FilterExpression": "#s = :status",
"ScanIndexForward": false,
"Limit": 100,
"ExpressionAttributeNames": {"#s": "status"},
"ExpressionAttributeValues": {
":t": {"S": "acme"},
":from": {"S": "2026-07-01T00:00:00Z"},
":to": {"S": "2026-08-01T00:00:00Z"},
":status": {"S": "failed"}
}
}
The filter is applied after the Query finishes, so the request consumes the same
read capacity whether it is present or not, and Limit caps items evaluated, not
items matched. CQL's LIMIT 100 returns 100 rows. This returns however many of the
first 100 items happened to be failures. The gap between ScannedCount and Count
in the response is your only signal that you read 100 items to keep three.
Per-query consistency becomes one boolean. Cassandra sets a level per operation:
LOCAL_QUORUM for a read you care about, ONE for a cheap one, sized against the
keyspace replication factor so that W + R > RF. DynamoDB has ConsistentRead: true
or the eventually consistent default, and it applies to tables and local secondary
indexes only. Every read from a global secondary index is eventually consistent, with
no override.
Those last two interact badly. The obvious fix for the filter is a GSI on status,
and taking it means that read can never be strongly consistent again. In Cassandra
you would raise the consistency level on that one query; here there is no level to
raise.
So the work that moves into your application is: composing and parsing the sort key,
paging on LastEvaluatedKey until you have collected 100 matches, and choosing
between paying to filter and reading an index you cannot read strongly.
Aggregates move too. CQL computes COUNT, MIN, MAX, SUM and AVG server-side
over the rows a query returns, and groups by primary-key columns:
SELECT COUNT(*) FROM app.tenant_order_events WHERE tenant_id = 'acme';
That count is cheap in Cassandra because it stays inside one partition. DynamoDB's
Select: "COUNT" gives you the same number and bills the same read units as fetching
every item, since it has to read each one to increment the counter. PartiQL adds
nothing here either: its SELECT has no aggregate functions and no GROUP BY.
DynoTable's SQL Workbench is where that shape lands instead. CQL would reject this
rollup, because GROUP BY accepts only primary-key columns and status is not one.
Here it is a single statement:
SELECT status, COUNT(*) AS events, SUM(amount) AS total
FROM tenant_order_events
WHERE tenant_id = 'acme'
GROUP BY status
It compiles to DynamoDB's native Query and Scan, planned against your real keys
and indexes, and does the grouping and the sums on the client. It supports GROUP BY
on any attribute plus COUNT and SUM, which PartiQL does not have. It adds no
server-side aggregate to DynamoDB, because nothing can; it removes the paging and
tallying loop you would otherwise write.
Working with DynamoDB
Once you have chosen DynamoDB, DynoTable is a desktop client for working
with your tables directly. It reads your standard AWS credential chain, so it connects
to the same regions and tables you already use — your data stays in DynamoDB, and there
is nothing to migrate.
Where a plain visual client only browses and scans, DynoTable adds a SQL Workbench that
expresses relational-shaped queries — JOINs, GROUP BY, and aggregates — while staying
within DynamoDB's access-pattern rules, and an AI agent that runs on your own AWS
Bedrock credentials. If you are hand-writing key conditions, filters, and update
expressions, the free
DynamoDB Expression Builder generates the correct
syntax for the SDK, CLI, and PartiQL without installing anything.
DynoTable is a closed-source commercial app; this page describes what it does, not how
it is built.
FAQ
Is DynamoDB based on Cassandra?
No. Neither is built on the other. Both trace back to Amazon's 2007 Dynamo paper —
Cassandra was created at Facebook by a co-author of that paper and also draws on Google's
Bigtable — but DynamoDB is a separate, fully managed AWS service and Cassandra is an
independent open-source project. They share design lineage, not code.
Cassandra vs DynamoDB for scale and cost?
Both scale horizontally to very large workloads. The real difference is the operating
model: DynamoDB's cost is pay-per-use (on-demand requests or provisioned capacity) with
no servers to run, so it shifts spend from operations to usage. Cassandra's software is
free, but you pay for and operate the infrastructure — nodes, storage, and the team to
run the ring — so its total cost depends heavily on scale and how it is managed.
Does Cassandra support SQL like DynamoDB?
Both offer SQL-like access rather than full relational SQL. Cassandra uses CQL, an
SQL-like language, and DynamoDB offers PartiQL, a SQL-compatible query language, alongside
its low-level API. Neither provides cross-partition JOINs natively; both are designed
around single-partition access patterns.
Related
- Learn how DynamoDB partition keys work and single-table design to model access patterns the DynamoDB way.
- Compare read modes in the DynamoDB consistency guide and billing in on-demand vs provisioned.
- Build queries fast with the free DynamoDB Expression Builder, then download DynoTable to work your tables natively.
References
- DynamoDB core components — AWS DynamoDB Developer Guide
- DynamoDB read consistency
- DynamoDB global tables
- PartiQL — a SQL-compatible query language for DynamoDB
- DynamoDB on-demand capacity mode
- Apache Cassandra architecture overview
- Apache Cassandra: Dynamo — replication and tunable consistency
Last verified 2026-07-13. Apache Cassandra is a trademark of the Apache Software
Foundation; referenced here for identification only.
Top comments (0)