Skip to main content
Interlaced eucalypt canopies with birds threading between the crowns, in a three-ink risograph print

Decision records

An architecture decision record is a short document capturing one decision, its context and its consequences, kept in the repo beside the code

Code shows what was decided. It rarely shows why, or what else was on the table. Those reasons end up in someone’s head, a chat log or a closed pull request, and an agent starting a fresh session can read none of them. A decision record puts them in the repo.

Definition

Martin Fowler defines an architecture decision record (ADR) as “a short document that captures and explains a single decision relevant to a product or ecosystem” (Architecture Decision Record, 2026). The form comes from Michael Nygard’s Documenting Architecture Decisions (2011), which gives each record five parts:

Most templates since add the options considered. Fowler also suggests a confidence level, and what change in circumstances should prompt a second look.

An example

A record for a decision most final projects have to make:

# 0002. Store data in SQLite on the Fly volume

Status: accepted

## Context

The app runs on one small Fly machine with one volume, as fly.toml fixes.
Messages and rooms must survive a redeploy. Expected load is one class.

## Options

- SQLite on the volume: no second service, and a backup is a file copy. Only one
  machine can write to it.
- Hosted Postgres: survives scaling out, but it's a second service to run, pay
  for and connect to.
- Server memory: the least code, and lost at every restart and deploy.

## Decision

SQLite on the volume, through the framework's ORM, with migrations applied when
the server boots.

## Consequences

The app can't run on a second machine without moving its data. Migrations must
run at boot, because Fly's release_command machine has no volume. Moving to
Postgres later means a data export and a record superseding this one.

Give the consequences the most care. The next person, or session, to touch the code needs to know what the choice ruled out, and a record that lists only benefits won’t tell them.

How they’re kept

adr-tools adds adr new and handles the numbering and superseding links. Backlog.md has a built-in backlog decision create, which writes to backlog/decisions/.

What gets one

A decision that is expensive to reverse, or that someone will ask about later. In a final project that’s the stack, what counts as a person, what persists and for how long, and how a change reaches everyone else. A library you could swap out in an afternoon, or a UI tweak, doesn’t need one; the commit message is enough.

The final project suggests them for the stack case in PROCESS.md, which can link to a record rather than restate it, and All at once asks you to write one down.

With an agent

Records help at two points in a session.

Before the decision, ask for options rather than an answer. An agent asked to “add a database” picks one and builds it, and the choice is buried in the diff. Asked for options, it lays out trade-offs you can judge:

lay out three options for where this app stores rooms and messages, with what each costs on one Fly machine. Don’t pick one and don’t write code yet

For a choice that depends on what you want, such as the stack, have it ask the questions instead:

read my README, then quiz me one question at a time about what this app needs: how many people at once, what has to persist, how fast updates travel. Give each option’s pros and cons. Don’t recommend a stack until I’ve answered

Then have it draft the record for the one you choose, with the options you ruled out, and check that the consequences say what gets harder.

After the decision, point CLAUDE.md at the records, so a fresh session reads them before it proposes something they already rule out:

## Decisions

Architecture decisions live in `doc/adr/`, one numbered file each. Read them
before proposing a change to the stack, storage or data model. To change one,
write a new record that supersedes it.

Further reading