Skip to content

Architecture decision records

An architecture decision record (ADR) captures one architecturally significant decision: its context, the options that were considered, what was decided, and what consequences were accepted. Standards say what must be true; runbooks say how to operate; ADRs preserve why the system is the way it is.

Government systems outlive the teams that build them. Without ADRs, the reasoning behind every important choice leaves with the people — and future teams either cargo-cult decisions that no longer make sense or accidentally reverse ones that exist for a legal or security reason.


When an ADR is required

Write an ADR for decisions that are expensive to reverse or that future maintainers will question:

  • Any deviation from the approved technology stack — a new framework, language, database, or significant dependency. The deviation is not approved until the ADR exists.
  • Choice of database engine, messaging pattern, or Blazor rendering mode for a new system.
  • How the system integrates with the shared platforms when more than one pattern is possible (for example, synchronous MConnect queries vs. MConnect Events subscriptions).
  • API style exceptions (REST is the default) and breaking-change strategies.
  • Anything where the team spent days evaluating options — if the analysis was worth days, it is worth a page.

Routine implementation choices that follow existing standards do not need ADRs. When in doubt, ask: "will someone in three years wonder why we did this?"

Where ADRs live

ADRs are part of the repository they describe, in /docs/adr/, numbered sequentially:

docs/adr/
  0001-use-postgresql-for-registry-storage.md
  0002-integrate-payments-via-mpay-not-direct-psp.md
  0003-blazor-wasm-rendering-for-citizen-portal.md
  • Numbers are never reused; a retired decision keeps its number and gets a status change instead of deletion.
  • ADRs are reviewed through the same pull request flow as code — the review of the ADR is the architecture review, with the discussion preserved in the PR.
  • An ADR is immutable once accepted: if the decision changes, write a new ADR that supersedes the old one and link them both ways.

Lifecycle

Status Meaning
Proposed Under discussion; not yet binding
Accepted Decision made; the record is now permanent
Deprecated No longer relevant (the component or context disappeared)
Superseded by ADR-NNNN Replaced by a newer decision

Template

The template follows MADR (Markdown Architectural Decision Records). Optional sections may be deleted; the required minimum is context, options, and outcome.

# NNNN — Short title stating the decision

* Status: proposed | accepted | deprecated | superseded by [ADR-NNNN](NNNN-example.md)
* Deciders: everyone involved in the decision
* Date: YYYY-MM-DD

Technical story: work item / ticket URL <!-- optional -->

## Context and problem statement

Describe the context and the problem in two or three sentences.
Articulating it as a question often helps.

## Decision drivers <!-- optional -->

* driver 1 — e.g., a constraint, regulation, or quality attribute
* driver 2

## Considered options

* Option 1
* Option 2
* Option 3

## Decision outcome

Chosen option: "Option 1", because — justification referencing the
decision drivers.

### Positive consequences <!-- optional -->

* ### Negative consequences <!-- optional -->

* accepted trade-offs, follow-up decisions now required

## Pros and cons of the options <!-- optional -->

### Option 1

* Good, because …
* Bad, because …

### Option 2

* Good, because …
* Bad, because …

## Links <!-- optional -->

* Refined by / supersedes [ADR-NNNN](NNNN-example.md)

Writing tips

  • State the decision in the title — "Use PostgreSQL for registry storage", not "Database".
  • Record honest negative consequences; an ADR with no downsides was not analyzed, only justified.
  • Capture the rejected options and why — that is the part future teams cannot reconstruct.
  • Keep it to one or two pages. An ADR is a record of a decision, not a design document.