Docs Automation Guide

System design document: the half that freezes and the half that refreshes

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

Most system design document templates blend two documents that have opposite requirements. One is a proposal written before the build, which is only useful if it stays exactly as it was. The other is a description of what got built, which is only useful if it never stops being current. Merging them produces a file that is wrong in half its sections within a year and trusted in all of them.

7 min readFor engineers writing a design doc that will still be read in two years

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

166/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Two documents wearing one name

The proposal answers what should we build and why this way. Problem statement, constraints, options considered, the option chosen, the risks knowingly accepted, the migration and rollback plan. Its value comes entirely from being a record of a moment, including the parts that turned out wrong.

The description answers what does this system consist of. Components, data flow, deployment, where things live. Its value comes entirely from matching reality right now, and it has no reason to remember what it said last quarter.

A template that puts both under one heading forces an impossible edit policy. Update the file and you destroy the record. Leave it and you publish a false description. Most teams end up doing neither and leaving the whole document to rot, which is the third option and the worst one.

The proposal half: dated, frozen, superseded rather than edited

Write it once, put a date and a status line at the top, and then treat it as immutable in the way an architecture decision record is immutable. When the plan changes, write the next document and mark this one superseded with a pointer. The corpus is then readable as a history of how thinking evolved, which is the thing nobody can reconstruct later.

The sections that earn their place are the ones about constraints rather than mechanics. Non-goals, because half of future confusion is about scope. Rejected options with the actual reason, because the second most common expensive mistake is re-proposing something that was already ruled out. Open questions, because a design doc that admits what it does not know is trusted more than one that does not.

The section that does not earn its place is a detailed component inventory. It will be out of date before the first release, and it is the part readers will most confidently misuse.

The description half: generate it from the branch

Everything the description half needs is declared in the repository. A repository-grounded doc produces an overview, a component inventory with one line of role each, the data flow, how the system builds and deploys, and short notes per notable directory, from a bounded read of the highest-signal files: infrastructure as code first, then containers, data, API specs, CI, and manifests, stopping at 40 files or 250KB.

Which of those classes leads is not a guess. On the first sync the file counts in the tree are tallied and a focus is proposed in one deterministic sentence, something like: mostly infrastructure code and Kubernetes manifests, 23 files, with 4 data model and API files. If the models and API definitions outnumber the infrastructure and CI files, the proposal flips to describing what the code does rather than the system around it. No model is involved in that step, which is why it costs nothing and always says the same thing about the same repository.

The diagram belongs in the same artifact, directly under the overview, so the reader sees the shape before the prose. In a generated doc that section is composed deterministically rather than written by a model, which means the embed line is either a real URL or an explicit instruction, never an invented link that resolves to nothing.

This is also the half that makes the proposal half readable years later. A frozen proposal next to a current description lets a reader see both what was intended and what exists, without either document having to pretend to be the other.

Reading a design doc against reality, a year later

The most valuable review of a design document happens long after the project ships. Generate the description from the branch as it stands, and read it next to the frozen proposal. Every divergence falls into one of two buckets: something drifted quietly, or a decision was taken and never written down.

Both buckets are worth emptying before the next design doc is started, because both are the raw material of the next proposal. Teams that skip this step tend to write the same design document twice, three years apart, with the same rejected options.

It is a cheap ritual: the description is regenerated on the tracked branch anyway, and a sync whose structure has not changed regenerates nothing, so the only cost is the half hour of reading.

If the comparison needs to be against a specific moment rather than against today, point a second diagram at a tag. One repository connection can back several diagrams, so the release that shipped with the design document sits beside the branch that shows what the system became, and the divergence between the two is the material for the next proposal.

FAQ

What belongs in a system design document?

Two separable halves. A proposal, written before the build, covering problem, non-goals, constraints, options considered with reasons for rejection, the chosen approach, risks, and migration or rollback. And a description of what exists, covering components, data flow, deployment, and layout. The first should freeze, the second should stay current.

Should a design document be updated after the system is built?

The proposal half should not be edited, because its value comes from being a record of what was intended and why. Supersede it with a new document instead. The description half should be kept current, which is far easier when it is generated from the repository rather than transcribed by hand.

How is a design doc different from an ADR?

Scope. An architecture decision record captures one decision with its context and consequences. A design document covers a whole change: problem framing, several decisions, sequencing, risk, and rollback. Both share the property that they describe a moment and should be superseded rather than edited.

Can the description half really be generated?

The parts declared in the repository can be. Components, deployment path, data flow, and directory layout are readable from infrastructure as code, container and orchestration files, data and API definitions, CI workflows, and package manifests. Intent, constraints, and rationale cannot be generated and stay hand-written.

What do I do when the design doc and the running system disagree?

Treat the disagreement as the finding rather than as a documentation defect. Each divergence is either unrecorded drift or a decision taken and never written down, and both are worth resolving explicitly. Doing it before the next design document starts is what stops a team re-litigating options that were already rejected two years earlier for reasons nobody kept.