Skip to content

ADR template (MADR format)

Copy-paste skeleton. Seven sections. At least two real options including do nothing. Signed by two engineers before the code lands.

How to use

Open with Status: Proposed. Do not start coding the chosen option until the ADR is signed and moved to Accepted. Replace every [...] with concrete content. If you cannot fill Considered Options with at least two real options, the decision is a default — not an ADR.

markdown
# ADR-NNN — [Title that names the decision, not the area]

Status:       Proposed | Accepted | Deprecated | Superseded by ADR-MMM
Date:         YYYY-MM-DD
Author:       [Name (role)]
Context-link: [Feature Brief · Initiative · related ADRs]

## Context and Problem Statement
[What is the situation? What forced this decision now? Bind to
 the cycle's brief or to a specific operational pressure. Two
 to four sentences.]

## Decision Drivers
[The forces and constraints. Two to five, no more.]
- [Driver 1 — performance, reversibility, cost, team familiarity,
   regulatory, security, etc.]
- [Driver 2]
- [Driver 3]

## Considered Options
[At least 2. Include *do nothing* explicitly. Number them.]
1. [Option 1 — one-line description]
2. [Option 2 — one-line description]
3. Do nothing — [what shipping without solving this looks like]

## Options Analysis
### Option 1 — [name]
Pros:
  - [...]
  - [...]
Cons:
  - [...]
  - [...]

### Option 2 — [name]
Pros:
  - [...]
Cons:
  - [...]

### Option 3 — Do nothing
Pros:
  - [Usually: faster cycle, no risk taken]
Cons:
  - [What we lose by not solving — specific to this cycle]

## Decision Outcome
Chosen: Option [N] — [name].

Rationale:
  [Why this option, anchored in the drivers. One paragraph.]

Trade-offs explicitly accepted:
  - [What we are choosing to lose]
  - [What we are choosing to defer]

## Consequences
Positive:
  - [...]

Negative:
  - [...]

Risks:
  - [Risk — Mitigation]

## Implementation Notes   (if relevant)
[Where this lives in the codebase. Cross-references to PRs,
 services, modules. Migration steps if needed.]

## Sign-off
Author:   [Name (role)] · [date]
Reviewer: [Name (role)] · [date]

[Move status to Accepted on sign-off.]

Worked example — the shape filled in

markdown
# ADR-014 — Idempotency keys for grading submissions

Status:       Accepted
Date:         2026-05-12
Author:       Esti (Tech Lead)
Context-link: Feature Brief — Grading shortcut (Gal) · ADR-009 (event bus)

## Context and Problem Statement
Gal sometimes submits a grade twice in 500ms when her keyboard
shortcut double-fires. The current code creates two ExamGraded
events. Billing then double-charges. This is `scenario-gap` at
the integration boundary.

## Decision Drivers
- Reversibility — double-charge corrections are expensive
- Cost of complexity — idempotency adds one column + one check
- Team familiarity — pattern used elsewhere in the codebase

## Considered Options
1. Idempotency key on the ExamGraded event (client-generated UUID)
2. Server-side debounce (window 1s)
3. Do nothing — accept double-charge, refund in support

## Options Analysis
### Option 1 — Idempotency key
Pros: deterministic, well-understood, reversible.
Cons: one extra column, requires consumer changes.

### Option 2 — Server debounce
Pros: minimal change to consumers.
Cons: hides the symptom, doesn't generalise, breaks legitimate fast resubmits.

### Option 3 — Do nothing
Pros: ships the feature unchanged.
Cons: ~8 support tickets/month at pilot scale; trust cost on financial data.

## Decision Outcome
Chosen: Option 1 — Idempotency key.

Rationale: reversibility is the top driver; option 2 trades
correctness for simplicity; option 3 pays the cost in trust.

Trade-offs explicitly accepted:
  - One extra column on the events table
  - Consumer migration deferred to next cycle

## Consequences
Positive: double-submit becomes safe by construction.
Negative: small schema migration; consumer change tracked as ADR-015.
Risks: Backfill of existing rows — Mitigation: lazy backfill on read.

## Sign-off
Author:   Esti (Tech Lead) · 2026-05-12
Reviewer: Maya (Senior Dev) · 2026-05-13

Where this lives in your project

ADRs live in the codebase, alongside the code they constrain — typically docs/adr/ or architecture/decisions/. They are versioned in git so the why travels with the code. Numbered sequentially; never deleted; superseded with reference to the new ADR.

What to do if a section resists

ResistanceWhat it meansWhere to go
Cannot name a second optionThe decision is a default, not an ADRClinic — An ADR with one option — file as TDB note instead
All options sound equally goodDrivers are unrankedRe-walk the drivers; rank them. The chosen option follows the top driver.
No trade-off seems necessarySome trade-off is hiddenEvery real choice loses something. Name what you are losing; if nothing, this is not an ADR.
Risks section is emptyThe team is over-confident or under-imaginativeWalk the chain. Where could this surface as a defect six weeks from now?
Status keeps driftingADR is read-once-write-neverMove it to Deprecated honestly or sign as Accepted. ADRs in Proposed indefinitely are dead.

See also

200apps · How We Work · NWIRE