authzed. The dual-write problem ← All demos
What this isOne upload handler, writing to two systems. Crash it at each point and see which one leaves them disagreeing.

Two systems. One request. No transaction across both.

Your application writes the file to its database, and the relationship to SpiceDB. Both need to happen. There is no transaction that spans them, so there is always a moment where one has landed and the other has not. Crash the handler at each point below and watch what each system is left holding.

The upload handler

pick a point and crash the server there

What each system is left holding

no crash yet

press a crash point
Application database
files table
SpiceDB
relationships
Five ways around it

Do nothing

Viable in the right context. If a user would notice and could fix it, or the content is not sensitive, the simplicity may be worth more than the guarantee.

simplest thing that could work; a stable platform drifts less
this kind of disagreement is hard to diagnose when it does happen

Out-of-band checking

Compare the two systems on a schedule against a source of truth, then remediate or flag the differences.

conceptually simple; one step beyond doing nothing
cost grows with your data, and fast-changing data gives false positives; the sync process can itself become a source of drift

Make SpiceDB the source of truth

For data that fits SpiceDB's model — a relationship is simply present or absent — drop the database column entirely. One write, no second system, no problem.

removes the dual write rather than managing it
you lose easy filtering, sorting and pagination — SpiceDB is not a general-purpose database

Event sourcing / CQRS

The API call becomes an event rather than a procedure. Separate consumers write to the database and to SpiceDB, and the runtime guarantees nothing is dropped.

any single consumer failure can be retried; the system converges
calls stop being RPCs, which often means significant rearchitecture

Durable execution

Write familiar procedural code and let the framework handle errors, rollbacks and coordination across services.

no rearchitecture; the code stays imperative and familiar
harder to know when the write landed, and the job runner becomes part of the request path

Transactional outbox

Write the intended SpiceDB change to an outbox table inside the same database transaction. A separate process reads the log and applies it. One transaction, so no dual write.

SpiceDB's TOUCH is idempotent, so the reader can retry until it succeeds
needs a reliable single-threaded reader; eventual consistency either way

Two things worth saying plainly

This is not a SpiceDB problem. Writing to an application database and a cache, or to two services, or to two databases, has exactly the same shape. Any system of sufficient complexity meets some version of it.

Reordering does not fix it. Try the SpiceDB-first option above. The dangerous window moves, it does not close — there is still a boundary where the process can die between the two writes. Adding transactional semantics to SpiceDB would move it again rather than remove it.

Based on authzed.com/blog/the-dual-write-problem, which goes further into each approach.