Skip to content

Architecture Decision Records (ADR)

Constrained choices, with rejected options.

An ADR records a technical decision that constrains future code. It names what was decided, what was considered and rejected, the trade-offs explicitly accepted, and the consequences. It does not record decisions that have no constraints — we are using TypeScript is not an ADR; we are using Mongoose rather than Prisma for this service because of [X], and accepting [Y] as a consequence is.

The ADR is the technical artifact that survives the developer leaving. It is the corpus's main weapon against the we made that choice for a reason but no one remembers it failure mode.

The MADR template

The corpus uses MADR (Markdown Architecture Decision Record) format. Every ADR has the same seven sections.

markdown
# ADR-NNN — [Title]

Status: Proposed | Accepted | Deprecated | Superseded by ADR-MMM
Date: YYYY-MM-DD
Author: [name]
Context-link: [Feature Brief, Initiative, related ADRs]

## Context and Problem Statement
What is the situation? What forced this decision now?

## Decision Drivers
The forces, constraints, and requirements that bound the choice.

## Considered Options
At least 2, ideally 3 + "do nothing".

## Options Analysis
Pros and cons of each option.

## Decision Outcome
The chosen option, with the rationale and the trade-offs we
are explicitly accepting.

## Consequences
- Positive: what gets better
- Negative: what gets harder
- Risks: what could go wrong

## Implementation Notes (optional)
Any specifics the implementing developer needs.

When to write one

The Tech Lead writes an ADR when:

  • A technical choice has consequences that will be felt outside the cycle.
  • A choice is being made between options that are non-trivially different.
  • A constraint is being applied that future developers will need to know about.
  • A trade-off is being explicitly accepted in service of something else.

The Tech Lead does not write an ADR for:

  • Routine choices inside an established pattern.
  • Style decisions covered by linters and conventions.
  • Decisions with one obvious option.

Why two options minimum

The corpus rule: never write an ADR with fewer than two options considered. The one obvious option is rarely as obvious as it feels. The act of writing down the rejected options is what reveals their weakness — and sometimes their strength. ADRs with one option are statements of preference; ADRs with two are decisions.

The third option is often do nothing — keep the current pattern, accept the friction, defer the decision. Naming do nothing explicitly with consequences forces the team to either accept the deferral or commit to the change.

States

StateMeaning
ProposedThe decision is being discussed; the ADR is being read by the team
AcceptedThe decision is in force; new code complies
DeprecatedThe decision is no longer the right one but has not been replaced
SupersededA new ADR has replaced this one; this ADR points to it

ADRs are never deleted. They are part of the record. Even superseded ADRs are useful — they tell future developers what was tried and why it changed.

Where ADRs live

In the corpus's reference layout:

text
/docs/architecture/adr/
  ADR-001-typescript-and-strict-null-checks.md
  ADR-002-mongoose-over-prisma-for-grading-service.md
  ADR-003-feature-flag-platform.md
  ...

ADRs are numbered sequentially. The number stays even when the decision is superseded — a deprecated ADR-002 still exists; ADR-019 supersedes it.

A short example

markdown
# ADR-014 — Use Bull (Redis) for grading job queue

Status: Accepted
Date: 2026-04-12
Author: Yossi (Tech Lead)
Context-link: Feature Brief — Grading Flow v2; ADR-006 (Redis cluster)

## Context and Problem Statement
Grading produces a sequence of background jobs (rendering reports,
notifying students, syncing to LMS). We need a job queue. The
existing services use ad-hoc setTimeout patterns; this is the first
service requiring a real queue.

## Decision Drivers
- Reliability of delivery (jobs must not silently fail)
- Operability (queue introspection, retry, dead-letter)
- Existing infra (Redis cluster from ADR-006)
- Developer familiarity

## Considered Options
1. Bull (Redis-backed) — Node ecosystem standard
2. SQS — managed, durable
3. RabbitMQ — full broker
4. Do nothing — keep ad-hoc setTimeout

## Options Analysis
[for each option, pros/cons]

## Decision Outcome
Bull. Reuses Redis cluster (no new infra). Mature in the Node
ecosystem. Trade-off accepted: Bull is in maintenance mode; we will
revisit when BullMQ migration is justified by team capacity.

## Consequences
- Positive: Job queue with retry, DLQ, and introspection in 2 days.
- Negative: Couples the grading service to Redis availability.
- Risks: Bull's maintenance status; mitigated by tracking BullMQ.

ADRs and the chain

ADRs are read in two places.

  • At Epic kickoff (Part 1) — to confirm the technical pattern the Epic depends on is current.
  • At postmortem (Volume V Part 4) — when an incident traces to a technical choice, the ADR is read. If the ADR is missing or wrong, the postmortem produces a new or replacement one.

A team whose ADR record is current and read is a team that has fewer of the who decided this conversations and more of the we decided this, here is what we'd accept changing conversations.

Part 7 — Sequence, Schema, API →

200apps · How We Work · NWIRE