# One writer per table

> The cheapest way to keep a shared database from becoming a distributed monolith.

- Type: playbook
- Published: 2026-05-04
- Topics: solution-architecture, database, boundaries
- Problem: Two or more services write to the same table and schema changes have become terrifying.
- Context: Shared-database architectures mid-migration toward services.
- Canonical: https://cmlonder.com/playbooks/one-writer-per-table

---
## Problem

Two or more services write to the same table, and schema changes have
become terrifying. Nobody can say with confidence what a column change
will break, so the schema stops evolving and workarounds accumulate
around it.

## Context

Shared-database architectures partway through a migration toward
services.

## Approach

Pick one owner per table and make every other writer go through it. The
owner is the service whose domain the data belongs to; if that is not
obvious, the owner is whoever gets paged when the data is wrong.

Do the reads last. Letting other services keep reading the table
directly while writes are consolidated is a perfectly good intermediate
state, and it is much cheaper than moving everything at once. Writes are
where the correctness problems are.

For each foreign writer, replace the direct write with a call to the
owner. Take the opportunity to make that call idempotent while you are
there, because you will want retries and you do not want to come back.

Once writes are consolidated, the schema becomes changeable again, and
that is the point of the exercise. Moving readers behind an API can then
happen gradually, table by table, driven by whichever change is
currently painful.

## Tradeoffs

Consolidating writes adds a network hop and a latency cost to paths that
used to be a local insert. It also makes the owning service a new
availability dependency for everyone who writes through it.

There is an organisational cost too: the owning team now receives change
requests from other teams and needs the capacity to serve them, or it
becomes the bottleneck everyone routes around.

## When this does not work

If the table is genuinely shared infrastructure with no domain owner,
such as an audit log that everyone appends to, forcing an owner creates
a chokepoint without a benefit.

It also does not help when the real problem is that the table is
modelling two different things. In that case the fix is to split the
table first, and ownership follows naturally.