- Published on
Cassandra 6.0-alpha1 and Accord Transactions — Where Does the 5-Year "General-Purpose Transaction" Promise Stand Now
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- Introduction — A Midpoint Check on a Five-Year Promise
- What Accord Promised — CEP-15's Goals
- What Actually Shipped — The Reality of the "Quarterly Alpha"
- Syntax — What BEGIN TRANSACTION Looks Like, and the One-Shot Model
- Modes and Costs — full, mixed_reads, off
- The Cost of Migrating Existing Tables — Migration Isn't Free
- Meanwhile, What You Can Use in 5.x — SAI and Vector Search, Realistically
- So When Should You Actually Start Caring
- Closing
- References
Introduction — A Midpoint Check on a Five-Year Promise
In Cassandra, "transaction" has long been a half-word. LWT (lightweight transaction) is Paxos-based CAS, so it only works within a single key — in the Cassandra documentation's own words, "Paxos only supports a single key". Atomically tying together multiple partitions has had to be faked by the application, with sagas or batches.
The proposal to change this is CEP-15: General Purpose Transactions. The tracking JIRA, CASSANDRA-17092, was created on 2021-10-30, and was only closed "Fixed" and merged into trunk on 2025-01-21. Then, as an artifact dated 2026-03-21, 6.0-alpha1 landed in the official Apache repository, and the release was announced on the dev list on April 3. Four and a half years from proposal to a runnable release. As of mid-July 2026, when this post is written, 6.0 is still nothing but alpha1, and the production line is 5.0.8 (2026-04-16).
So it is worth taking stock right now — what was promised, what actually shipped, what constraints the docs spell out, and when you should actually start caring.
What Accord Promised — CEP-15's Goals
Carried over verbatim, the goals CEP-15 states are these.
- General-purpose transactions — any keys in the database can be tied together at once
- strict-serializable isolation
- Optimal latency — every transaction takes a single WAN round trip under normal conditions
- Optimal fault tolerance — latency and performance are unaffected by a minority of replica failures
- Scalability — creates no new bottleneck
- Support for live migration from Paxos
What sets it apart from existing systems is having no leader. The CEP document itself classifies prior art this way — FaunaDB and FoundationDB use a global leader (a scalability bottleneck); DynamoDB, CockroachDB, and YugabyteDB use a complex combination of transaction logs and per-key leaders; and the academic leaderless approach (the EPaxos family) has never actually been used in a real database. Accord is an attempt to put that third path into a production database. The long-term plan is also spelled out in the document — this work is expected to replace Paxos in the project; the two protocols will coexist during a transition period, after which Paxos will be deprecated.
One caveat. "A single WAN round trip" is a protocol-level claim, and no official millisecond-scale benchmark numbers exist anywhere in the official docs as of this writing. As we'll see later, even the release notes are still in placeholder state.
What Actually Shipped — The Reality of the "Quarterly Alpha"
The 6.0-alpha1 CHANGES.txt actually contains these lines.
6.0-alpha1
* General Purpose Transactions (Accord) [CEP-15] (CASSANDRA-17092)
* Automated Repair Inside Cassandra [CEP-37] (CASSANDRA-19918)
* ...(excerpt — plus TCM, the constraints framework, UCS parallel compaction, and more)
Accord isn't the only thing that arrived. NEWS.txt's list of 6.0 new features includes CEP-21 Transactional Cluster Metadata (TCM), the CEP-37 automated repair scheduler, the CEP-42 constraints framework, and the adoption of JDK 21 with Generational ZGC as the default GC. Because TCM changes the upgrade procedure itself, a warning sits at the very top of NEWS.txt saying it "requires operational steps different from previous upgrades."
But you have to read the nature of the release precisely. The April 3 announcement says this — this is a quarterly alpha release of the 6.0 series, the cassandra-6.0 branch has not yet been created, this release does not kick off the alpha quality lifecycle guidelines, and quarterly alphas are for development and testing purposes only. The intent is clear from the November 2025 release cadence proposal thread — a quarterly alpha is nothing more than "a tag for a specific date that was confirmed to build and voted on," with no backports and no support.
The formal cycle began right after that. The 2026-04-09 thread discussed branching cassandra-6.0 and 6.0-alpha2 ("this kicks off the alpha release lifecycle"), and indeed the repository now has a cassandra-6.0 branch, with trunk having moved on to 7.0 development. But as of mid-July, the only 6.0-series artifact on the official download page is alpha1. No beta, and no promised GA date.
There's a backstory tangled up in the version number too. This release was originally slated to be 5.1, but the December 2024 dev-list discussion "5.1 should be 6.0" settled on bumping the major version, on the grounds that TCM and Accord amount to a generational shift that fundamentally changes how the system operates. As a result, 5.1 never shipped, and the next version became 6.0.
There are also plain signs that the docs are lagging behind the code. NEWS.txt's 6.0 new-features section still carries the line "below is a placeholder and will be fixed soon," and Accord doesn't even have an entry in the new-features list. The CQL transactions user guide (transactions.adoc) exists on trunk but not yet on the cassandra-6.0 branch. Unless you're testing the alpha yourself, reading the repository's primary source documents is more accurate at this stage than blog posts or talk decks.
Syntax — What BEGIN TRANSACTION Looks Like, and the One-Shot Model
The syntax laid out in trunk's transactions guide looks like this.
BEGIN TRANSACTION
LET sender = (SELECT balance FROM accounts WHERE user_id = ?);
SELECT sender.balance; -- returning results only works before modifying statements
IF sender.balance >= 100 THEN
UPDATE accounts SET balance = balance - 100 WHERE user_id = ?;
UPDATE accounts SET balance = balance + 100 WHERE user_id = ?; -- a different partition is fine too
END IF
COMMIT TRANSACTION
A read-condition-write spanning different partitions (and different tables) becomes a single atomic unit. This was impossible with LWT.
The key point is that this is not an interactive transaction. Rather than the RDBMS-style model of keeping BEGIN open and running multiple statements back and forth with application logic, it's a one-shot model that submits the entire transaction as a single statement, all at once. The internal doc (CQL on Accord) explains why — the full set of keys a transaction will touch must be declared up front, before execution, and cannot change during execution. This upfront declaration is the price paid for leaderless dependency tracking.
Summarizing the constraints spelled out in the docs.
- A LET's SELECT must return exactly one row, must specify the entire partition key with equality, and cannot use range conditions, multiple partitions, or aggregates
- Inside a transaction block, counter tables, aggregate functions, ORDER BY and GROUP BY, custom TTLs/timestamps, and range DELETE cannot be used
- IF conditions support only AND (no OR), and null comparisons are always false
- No row-reference arithmetic in a SET clause — something like
SET balance = sender.balance - 100is not allowed; the computed value must be passed as a parameter - A SELECT that returns results must come before any modifying statement; to see post-modification values you need a separate query after commit
The docs also include a performance guide, and its footnote is an honest reflection of how mature this feature really is — it says to start with 5 LETs and fewer than 3 partitions, while stating outright that this is "a suggested guideline, not an empirically derived limit." In other words, the project itself doesn't yet have measurement-based tuning guidance either.
Modes and Costs — full, mixed_reads, off
Accord isn't something you flip on globally — it's selected per table. After turning on accord.enabled: true in cassandra.yaml, you set transactional_mode on each table. Per the operations guide, there are three modes.
off (default) — Same as Cassandra has always been. SERIAL goes through Paxos, everything else takes the eventual-consistency path, and transaction statements are rejected.
full (recommended) — All reads and writes go through Accord. Because Accord knows there is no non-transactional reader, it can use single-replica reads and asynchronous commit, and per the docs, WAN round trips drop from 2 to 1. In exchange, any specified consistency level is ignored.
mixed_reads — Writes go through Accord, and non-SERIAL reads use the existing path. In this case, existing reads need to be able to see Accord's writes, so a synchronous commit at the requested consistency level is required, bringing the total WAN round trips to 2. The docs themselves recommend that "most users should go straight from off to full."
This is where a constraint that any multi-DC operator absolutely needs to know about shows up. The consistency levels Accord supports are, in full, reads ONE/QUORUM/SERIAL/ALL and writes ANY/ONE/QUORUM/SERIAL/ALL. The LOCAL family (LOCAL_QUORUM, LOCAL_ONE, LOCAL_SERIAL) and TWO/THREE are not supported, and requests for unsupported levels are rejected. If your workload has run multi-region by leaning on DC-local latency, current Accord simply has no way to express that requirement. CEP-15 itself lists a LOCAL_SERIAL replacement (a non-global operating mode) only as a "future goal." As a bonus, the docs also state that specifying ONE as the commit consistency level is silently executed as QUORUM.
There is also a cost around performance that the docs honestly write down. A LIMIT-ed partition-range read gets split and executed across as many command stores per node (default: the number of available processors) as exist, then merged at the coordinator, so memory and CPU are amplified proportionally. Paging is a separate transaction per page, so it does not guarantee linearizability of the overall result, and partition-range reads do not produce strict-serializable results. The internal docs state flatly that range transactions have more expensive dependency tracking and more frequent conflicts than key transactions.
The Cost of Migrating Existing Tables — Migration Isn't Free
For a new table it's simple enough — just create it WITH transactional_mode = 'full' — but an existing table has to go through a live migration. The reason is interesting: Accord has to replay reads during transaction recovery, so reads must be deterministic, and non-SERIAL writes break that determinism. So migration is a two-stage process.
- Stage 1, after ALTER — non-SERIAL writes go through Accord (with a synchronous commit at the requested consistency level), while SERIAL stays on Paxos. A data repair (full or incremental) has to run once so Accord can safely read the existing data.
- Stage 2 — every operation goes through Accord. However, a Paxos key repair must precede each key, adding at least one WAN round trip, and because Paxos writes are only visible at QUORUM, Accord also has to read at QUORUM. Completing the migration requires both a full repair and a Paxos repair — incremental repair does not work here, because it cannot include the data a Paxos repair propagated.
There is no automation for triggering repairs. Per the docs, if you are already running compatible repairs on a regular schedule, migration will eventually finish on its own; otherwise you have to push it through directly with nodetool consensus_admin finish-migration. Requests that touch a range still under migration pick up at least one extra WAN round trip from shuttling between the two systems. The fortunate part is that the way back (from full to off) is also documented — it is a single stage: Accord repair, then revert to Paxos.
Operationally, in summary: latency goes up during the migration window, a heavyweight full repair is mandatory, and orchestrating it is on you (there is no measured case yet of how much 6.0's CEP-37 automated repair will actually reduce that burden).
Meanwhile, What You Can Use in 5.x — SAI and Vector Search, Realistically
While Accord stays in alpha, SAI and vector search — introduced by 5.0 (GA 2024-09-05) — have already been running as GA for close to two years. Here, all you need is to set expectations correctly.
The official FAQ draws its own line around SAI (Storage-Attached Indexing) — SAI is not an enterprise search engine but is, at its core, a filtering engine. String operators are limited to equality and the CONTAINS family; LIKE is not supported. Index disk overhead is documented at 20-35% over unindexed data, and if you AND together three or more SAI indexes in one query, only two are handled as indexes and the rest fall back to post-filtering. Queries without a partition key are still scatter-gather, and the docs directly warn that, worst case, a high-cardinality column can turn into a full-cluster scan. This is why SAI complements rather than replaces the basic principle of data modeling — partition-key-centered design.
Vector search is built on JVector (a DiskANN-family ANN library); the VECTOR type supports up to 8K (2^13) dimensions, and an ANN query's LIMIT must be 1,000 or below. There are three similarity functions — cosine (default), dot product, and Euclidean — and one trap the docs note is worth remembering: dot product is faster (50% by the docs' own claim), but using it on unnormalized embeddings silently produces meaningless results. Index options cannot be changed once created, so you have to drop and recreate. It is better viewed not as a replacement for a dedicated vector DB, but as an option for when you want embeddings sitting right next to data you already have in Cassandra. A per-engine comparison is covered in the 2026 database engines deep dive.
So When Should You Actually Start Caring
If you're in production right now. Stay on 5.0.x. Because 4.0's support ends alongside the 6.0 release and 4.1's ends alongside 7.0 (per the official download page), upgrade pressure toward 5.0 is already real. Note ahead of time that a 6.0 upgrade plan involves a separate operational procedure — the TCM transition.
Where testing Accord is worth it. Workloads that have piled up saga/batch code to fake LWT across multiple partitions, and latency profiles where single-region or global QUORUM is acceptable. If that's your team, it's worth measuring your own workload's conflict patterns against the alpha ahead of time. Just remember: quarterly alphas come with no support and no backports.
Where you don't need to care yet. Workloads running multi-DC on LOCAL_QUORUM (there is no way to express that), workloads that depend on counter tables (transactions are not possible), migrations expecting RDBMS-style interactive transactions (it is a one-shot model), and any case where you want to decide based on benchmark numbers — there is nothing to look at, since no official numbers exist yet.
Closing
To sum up: Accord is an ambitious design — leaderless, multi-partition, strict-serializable transactions — whose 2021 proposal only arrived in a runnable form in 2026. The code has landed in 6.0-alpha1, but that alpha is closer to "a date tag confirmed to build," the release notes are placeholders, and there is no official material saying anything about performance beyond the protocol's round-trip count. The one-shot syntax model, the absence of LOCAL consistency levels, and migration requiring a full repair — these three are the practical boundaries right now.
Put the other way around, this is also a rare moment when all the raw material you need for judgment is out in the open. CHANGES.txt, the in-tree docs, and the dev list alone draw this much of a picture. I'll check back in once a beta ships and benchmarks start appearing — until then, I'd recommend basing any decision about this feature on reading the documents above directly, not on presentation slides.
References
- CEP-15: General Purpose Transactions — Apache Cassandra Wiki
- CASSANDRA-17092 — CEP-15: Accord Beta (JIRA, created 2021-10-30 / Fixed 2025-01-21)
- [RELEASE] Apache Cassandra 6.0-alpha1 released — dev list announcement (2026-04-03)
- Quarterly alpha / release cadence proposal thread (2025-11)
- Branch cassandra-6.0 and 6.0-alpha2 — dev list (2026-04-09)
- [DISCUSS] 5.1 should be 6.0 — dev list (2024-12-10)
- 6.0-alpha1 official artifact (archive.apache.org, 2026-03-21)
- cassandra-6.0 CHANGES.txt · NEWS.txt
- Accord Transactions user guide (trunk)
- Onboarding to Accord — operations guide (cassandra-6.0)
- CQL on Accord — internal design doc (cassandra-6.0)
- SAI FAQ (cassandra-5.0) · Vector search data modeling (cassandra-5.0)
- Apache Cassandra release/EOL status — endoflife.date · Official download page