Reference · Printable Template
Michael Nygard's format, ready to copy into your repo — with a worked example and the six-item checklist that separates a record from a press release.
An Architecture Decision Record is a short text file — one
to two pages — capturing one architecturally significant decision and its rationale. The format
below is Nygard's original (2011),
with an explicit Alternatives considered section added, as taught in
Lesson 05. Keep ADRs in the repo
(e.g. docs/adr/), numbered sequentially, named after the decision:
0012-use-event-driven-messaging.md. Never edit an accepted ADR — write a new one
that supersedes it.
Copy this into a new Markdown file and fill in every section — in prose, not bullet fragments. If a section feels hard to write, that's the section doing its job.
# ADR NNNN: [Short noun phrase naming the decision]
## Status
Proposed | Accepted (YYYY-MM-DD) | Deprecated | Superseded by ADR-NNNN
## Context
What forces are at play — technical, organizational, project-local?
What constraint or event makes a decision necessary *now*?
Write it so a reader with zero tribal knowledge could follow.
Neutral tone: describe forces, don't argue for a winner.
## Decision
"We will ..." — active voice, full sentences.
The response to the forces above, and its scope
(what this decision does *not* cover).
## Alternatives considered
For each rejected option: what it is, its genuine strengths,
and the specific reason it lost *in this context*.
Test: would an advocate of this option call your summary fair?
## Consequences
The resulting context after the decision — ALL of it:
- Positive: what gets easier or better.
- Negative: what gets harder, riskier, or more expensive.
(There is always at least one. Find it.)
- Neutral: new facts of life — things now true that are
neither good nor bad, but must be known.
Short and real-shaped — about the length a good ADR actually is.
| ADR 0012: Use event-driven messaging between Orders and Inventory | |
|---|---|
| Status | Accepted (2026-06-12) |
| Context | Checkout calls Inventory synchronously to reserve stock. When Inventory slows, checkout p99 latency spikes and sale-day bursts cause cascading failures; last quarter's promotion produced a 40-minute checkout outage. Analytics now also needs a feed of stock changes, which would add a third synchronous dependency. Stock reservations must not be lost, but the business accepts a short delay between "order placed" and "stock confirmed." |
| Decision | We will publish an OrderPlaced event to a message broker. Inventory
consumes it and reserves stock asynchronously; checkout confirms the order as
pending immediately. This ADR covers the Orders→Inventory interaction only, not
a general move to event-driven architecture. |
| Alternatives considered | Keep the synchronous call, add a circuit breaker and tighter timeouts.
Simplest option: no new infrastructure, and checkout keeps an immediate, definitive stock
answer. Rejected because it degrades rather than removes the availability coupling — sale-day
bursts still push Inventory's latency into checkout. Point-to-point queue between the two services. Lighter to operate than a broker and still absorbs bursts. Rejected because Analytics (and likely others) need the same stream; a second consumer would force a redesign within two quarters. |
| Consequences | Positive: checkout latency is decoupled from Inventory health; bursts queue
instead of cascading; new consumers subscribe without touching Orders. Negative: a customer can now place an order that later fails stock reservation — we must build a compensating "order rejected" flow and notification; debugging spans an async hop, so tracing is harder; the broker is new operational surface (on-call, upgrades, capacity). Neutral: events must be partitioned by product ID to keep per-item ordering; Inventory consumers must be idempotent, since the broker delivers at-least-once. |
Run every draft against these six before you call it done — they're also the rubric your Lesson 05 lab is reviewed against.