Topic: when to retire an ADR
When to Retire an ADR — Deprecation, Supersession, and the Never-Delete Rule
Most ADR guidance covers creation. The harder question comes two or three years later: a service was sunset, a team reorganized, a framework was deprecated upstream, and the ADRs that governed it are now archaeology. Three paths: supersede (decision replaced by a named new ADR), deprecate (decision no longer operative, no single successor), or delete (almost never right). Getting this wrong in the "just delete it" direction corrupts the audit trail — it removes the evidence that the decision existed, which is precisely what the ADR practice is designed to preserve.
TL;DR
When the Decision section became false and a new ADR explicitly replaced it: supersede (two-file atomic PR, bidirectional pointers). When the Context became void — the component was removed, the area dissolved — but there's no named replacement decision: deprecate (one file, one-sentence reason in Notes, Status → Deprecated). When a Proposed ADR's PR was closed without merging: the only justified deletion. In all other cases, the ADR stays — stale archaeology is exactly what the ADR practice is for.
Three paths for an obsolete ADR
When an ADR no longer reflects current practice, there are exactly three correct responses. Two of them preserve the audit trail; one destroys it. The right choice depends on why the ADR became obsolete — specifically, whether it was the Decision section or the Context section that became untrue.
| Path | Condition | Operation | Files touched | CI check | Right when |
|---|---|---|---|---|---|
| Superseded | A new ADR explicitly reversed the choice — the Decision section is now factually false | Set old ADR Status: Superseded + Superseded-by pointer; new ADR gets Supersedes pointer | Two files in one atomic PR | CI supersession integrity job verifies both pointers resolve to existing files | The team chose option B over option A, and option B is documented in a named ADR |
| Deprecated | The decision's context is void — the component no longer exists, the area dissolved, no replacement decision was made | Set Status: Deprecated; add Notes entry with date and one-sentence reason; optionally add Deprecated-by pointer | One file only | No CI file-existence check on Deprecated-by (pointer is to a PR, ticket, or URL, not another ADR) | The whole architectural area went away and there is no new ADR to name as successor |
| Deleted | A Proposed ADR whose PR was closed without merging — it never reached the canonical branch | Close the draft PR; no commit needed. If the file accidentally landed on the default branch before the PR was closed, a cleanup commit is acceptable | One file removed; no other ADR references it | No CI check can catch an invalid deletion — the file simply disappears | The ADR never became Accepted, never governed any implementation decision, and no other ADR cross-references it |
The core conceptual distinction: Superseded means the Decision section is now false — the team made option A; they now make option B, and the new ADR naming option B exists. Deprecated means the Context section is now void — the architectural question the ADR was answering no longer applies, because the system it governed is gone.
A concrete pair of examples makes this tangible. An ADR titled "Use Redis for job queue backend" becomes Superseded when the team writes "Switch to Valkey for job queue backend" and explicitly reverses the choice: the Decision section of the old ADR now describes an option the team explicitly rejected. The same ADR becomes Deprecated if the team removes the job queue layer entirely in favor of Temporal (a managed workflow engine) and never writes a "use Temporal" ADR because Temporal was a vendor procurement decision, not an ADR-level architectural call. In the deprecation case, the old ADR's Decision section is not false — the team did pick Redis — but the context (there is a job queue layer) simply no longer exists.
The deprecation protocol — one file, not two
Unlike supersession, deprecation touches exactly one file. There is no second ADR to write and no bidirectional pointer to maintain. The three changes are:
- Status: Deprecated — this is the canonical value. Do not use Obsolete, Retired, Archived, or Inactive. These non-canonical variants cause the ADR GitHub Action auto-index job to treat the file as having an unrecognized status, which produces a broken row in the generated index table. The five canonical values the tooling knows are Proposed, Accepted, Superseded, Deprecated, and Rejected.
- A Notes entry in the format
Deprecated YYYY-MM-DD: [one-sentence reason].Written at the top of the Notes section in reverse-chronological order, consistent with how all Notes entries are written. - Optionally: Deprecated-by: [pointer] — a PR URL, Jira ticket, migration guide URL, or commit SHA that explains why the decision became irrelevant. This field is a convention, not a standard, and is not verified by CI.
Here is what the change looks like for the two most common ADR formats.
Nygard format — before:
# ADR 0023: Use Redis for asynchronous job queue
Status: Accepted
## Context
The application needs a durable queue for background email delivery and PDF
generation jobs. We evaluated Redis (via Sidekiq) and RabbitMQ.
## Decision
We will use Redis via the Sidekiq library for background job processing.
## Consequences
Positive: Sidekiq's visibility dashboard is excellent. Redis reuse (already
used for session caching) keeps infrastructure simple.
Negative: Redis is not a message broker by design; if queue semantics grow
complex we may need to revisit.
Nygard format — after deprecation:
# ADR 0023: Use Redis for asynchronous job queue
Status: Deprecated
Deprecated-by: PR#847 — Redis queue removal (migrated to Temporal)
## Context
The application needs a durable queue for background email delivery and PDF
generation jobs. We evaluated Redis (via Sidekiq) and RabbitMQ.
## Decision
We will use Redis via the Sidekiq library for background job processing.
## Consequences
Positive: Sidekiq's visibility dashboard is excellent. Redis reuse (already
used for session caching) keeps infrastructure simple.
Negative: Redis is not a message broker by design; if queue semantics grow
complex we may need to revisit.
## Notes
Deprecated 2026-05-31: job queue layer removed entirely in PR #847; background
work migrated to Temporal Cloud. No replacement ADR — Temporal is a vendor
procurement decision managed at the infrastructure level.
MADR frontmatter format — before:
---
status: Accepted
date: 2024-03-10
deciders: alice, bob, carol
---
# Use Redis for asynchronous job queue
MADR frontmatter format — after deprecation:
---
status: Deprecated
deprecated-by: "PR#847 — Redis queue removal"
date: 2024-03-10
deciders: alice, bob, carol
---
# Use Redis for asynchronous job queue
Note that in both formats the original Context, Decision, and Consequences sections are left untouched. Those sections are permanent history. The deprecation is signaled entirely through the Status field, the optional Deprecated-by pointer, and the Notes entry — the three additions that sit outside the historical body of the decision.
The Deprecated-by field — optional and CI-silent
The Deprecated-by field is a convention, not a standard — it appears in neither the original Nygard template nor the MADR specification. It exists because practitioners found it useful to record a specific artifact that explains the deprecation, parallel to the way Superseded-by records the successor ADR for a superseded decision.
The key difference from Superseded-by: Deprecated-by is not verified by the CI supersession integrity check. The integrity check (job 3 in the ADR GitHub Action workflow) works by resolving every Superseded-by value as a filename in the decisions directory and failing if the file does not exist. It cannot apply the same logic to Deprecated-by because the pointer is not an ADR file — it is typically a PR URL, a Jira or Linear ticket, a migration guide URL, or a commit SHA. None of these are ADR filenames, so filename resolution doesn't apply.
Valid values for Deprecated-by include:
- A PR number and title:
deprecated-by: PR#847 — Redis queue removal - A full PR URL:
deprecated-by: https://github.com/org/repo/pull/847 - A Jira or Linear ticket:
deprecated-by: INFRA-2201 — decommission legacy queue - A runbook or migration guide URL
- A commit SHA:
deprecated-by: a3f9c12 — removed Sidekiq and redis gem - Another ADR that covers the successor domain at a higher level of abstraction — but note this is rare; if there is a named successor ADR, supersession is usually the right call, not deprecation
When to omit the field entirely: if the deprecation resulted from a diffuse context-collapse — a team reorganization, a general platform migration, a gradual sunset without a single identifiable artifact — write a plain Notes entry describing the situation and leave Deprecated-by out. A vague Deprecated-by value adds noise without adding traceability. The Notes entry is always sufficient on its own; Deprecated-by is only worth including when a specific artifact is the authoritative explanation and a future reader would clearly benefit from the direct link.
Supersession vs deprecation — the decision table
The distinction between supersede and deprecate collapses in practice to a single question: is there a named successor ADR? If yes, supersede. If no, deprecate. But the scenarios that arise in real ADR directories are messier than that binary. This table covers the cases teams most often ask about.
| Scenario | Right call | Why |
|---|---|---|
| Switched from Redis to Valkey as the job queue backend | Supersede | A new ADR exists ("Switch to Valkey for job queue backend"). The Decision section of the old ADR named Redis; following it today means setting up Redis. The choice is factually reversed. Write the new ADR, set old ADR to Superseded, add bidirectional pointers. |
| Redis queue removed entirely in favor of Temporal (workflow engine) — no new "pick Temporal" ADR was written because Temporal is a vendor procurement decision | Deprecate | There is no "pick Redis or Valkey" successor decision. The entire job-queue architectural layer is gone. The old ADR's context is void. Deprecated-by: PR#847 is the right pointer; no new ADR is needed or appropriate. |
| The team that owned the ADR was merged into another team — no relevant architectural change occurred | Keep (no change) | Team org changes don't make an architectural decision irrelevant. The decision still governs the system it governs. If the new team disagrees with the decision, they should write a superseding ADR — not deprecate on organizational grounds. |
| Library used in the ADR went end-of-life (e.g., the Sidekiq version the ADR chose is now EOL) | Deprecate only if the ADR is about the library itself; annotate if the ADR is about a higher-level choice the library implements | An ADR titled "Use Redis for job queuing" is about the architectural call, not the specific Sidekiq version. Annotate it with a Notes entry explaining the EOL situation and the version upgrade decision. An ADR titled "Use Sidekiq 6 for background processing" is specifically about the library — deprecate it and write a new ADR for the replacement. |
| Decision was reversed without a successor ADR being written first | Write the successor ADR first, then supersede | Do not deprecate when the decision was actually reversed. Deprecation says "the context dissolved." If the team made a new choice, that new choice deserves its own ADR. The correct sequence is: write new ADR → supersede old ADR in the same PR. Using Deprecated as a workaround for "we changed our mind but didn't write it up" creates an audit trail that says "this area dissolved" when actually the team made a deliberate new decision. |
| A component referenced by the ADR is removed, and the ADR is about a cross-cutting concern that partially still applies | Annotate, not deprecate | If the ADR is about a pattern or principle that applies beyond the removed component, it should not be deprecated just because one of its referenced systems is gone. Add a Notes entry: "Update YYYY-MM-DD: the Redis component this ADR governed was removed in PR#847. The caching-strategy principles in this ADR continue to apply to the Memcached and in-process cache layers." Deprecation applies to the entire decision's context being void — not to a partial obsolescence. |
Why deletion is almost never right
The instinct to delete an ADR that is "no longer relevant" is understandable — directories fill up, stale files feel like clutter, and a lean decision log seems more useful than a sprawling one. But deletion breaks the audit trail in three distinct ways that are hard to repair after the fact.
1. Deleted files still appear in git history — and create orphan CI failures. If any other ADR in the directory ever pointed at the deleted file with a Superseded-by or Supersedes line, the CI supersession integrity check will now fail on every PR that touches the decisions directory. The check resolves every pointer by filename; a pointer to a deleted file is an unresolvable reference. The reviewer sees a CI failure, traces it to a missing file, and has to reconstruct — from git history — why the file was deleted and what the relationship was. This is more maintenance burden than the original stale ADR created.
2. The absence of an ADR is indistinguishable from "no decision was made." A Deprecated ADR says: "this decision was made; we governed this system this way; the context has since dissolved." A missing ADR says nothing — a reader examining the directory cannot tell whether the team carefully considered and then deprecated the decision, or whether the decision simply never existed. The ADR practice's core value is making the history of architectural reasoning inspectable. Deletion makes the past look like a blank rather than a superseded or deprecated choice.
3. Adjacent ADRs that reference the deleted file by number become orphaned references. It is common for ADRs to cite related decisions: "This decision supersedes ADR-0023 (see 0023-redis-job-queue.md) and should be read alongside ADR-0031 (0031-background-processing-strategy.md)." If ADR-0023 is deleted, every ADR that cites it now contains a dead reference. Future engineers reading those ADRs encounter a gap in the chain they cannot follow without going into git history — which defeats the purpose of keeping the ADR directory as a navigable, self-contained record.
The one justified deletion is a Proposed ADR whose PR was closed without merging. A Proposed ADR that never reached the canonical branch never governed any implementation decision; it never appeared in another ADR's Supersedes or Superseded-by line; and its cleanup naturally happens at PR close rather than via a separate deletion commit. If such a file accidentally landed on the main branch before the PR was closed, a brief cleanup commit is acceptable — but add a commit message that explains the deletion was of an unmerged draft, so the git log entry is interpretable.
The archive question
Some teams propose moving stale ADRs to an archive/ subdirectory as an alternative to deletion — a way of cleaning up the "active" decisions directory without losing the files. This approach sounds reasonable but causes a specific class of breakage that is tedious to repair.
Every supersession pointer uses a filename relative to the decisions directory: Superseded-by: 0023-redis-job-queue.md. Moving the file to archive/0023-redis-job-queue.md silently breaks every pointer that names it. The CI supersession integrity check, which resolves pointers relative to the decisions directory, will fail for every ADR that references the archived file. Fixing those pointers requires editing every referencing ADR to update its Superseded-by value — which means those ADRs now have a misleading last-modified date and an irrelevant change in their git blame.
The correct mental model: ADR files stay in doc/decisions/ forever. The Status field is the archive signal. A directory that contains ADRs at Status: Deprecated and Status: Superseded alongside ADRs at Status: Accepted is not cluttered — it is correct. The accepted ADRs describe current practice; the superseded and deprecated ones describe history. Both are needed for the audit trail to be coherent.
If the concern is visual clutter when browsing the directory, the right solution is tooling: the ADR GitHub Action auto-index job generates a status table and can filter by status for display purposes. The Log4Brains static site generator renders a filterable browsable view of the same files. Neither requires moving or deleting files — they read Status from the frontmatter and present the directory accordingly.
"Archiving" is a classification you apply to a repository's ADR practice as a whole — for example, "this repository is read-only; no new decisions are being made" — not to individual ADR files. A repository-level archive annotation belongs in the decisions directory README, not in individual file relocations.
Mass deprecation when a component is removed
When a service is decommissioned or a significant architectural layer is removed, several ADRs may become obsolete simultaneously. A payment service removal might deprecate the ADR that chose Stripe, the ADR that chose the webhook retry strategy, the ADR that chose PCI-scoped network isolation, and the ADR that chose the reconciliation job schedule — four separate files that all governed the same removed component.
The protocol for mass deprecation:
- Open a single PR that touches only the ADRs covering the removed component. Do not intermix the deprecation with unrelated changes. The PR description is the audit artifact that explains why all these files changed together.
- Each ADR gets two changes only: Status changed to Deprecated, and a Notes entry in the format:
Deprecated YYYY-MM-DD: [component name] removed in PR #NNN. No replacement ADR — [one-sentence reason, e.g. "migrated to managed service Stripe Treasury with no equivalent local decision"]. - Add a Deprecated-by field pointing to the removal PR:
Deprecated-by: PR#847 — payment service decommission. When all the ADRs in a mass deprecation share the same removal PR, the same Deprecated-by value appears in every file — this is correct and intentional. - The PR description lists every file changed and explains the component removal. Link the removal PR or ticket explicitly so the relationship is bidirectionally traceable: the removal PR links the ADR update PR; each ADR's Notes entry links the removal PR.
One common anti-pattern: suppressing or combining the ADR deprecation commits into the removal PR itself to "keep the diff clean." Resist this. The ADR updates belong in a separate, clearly-labeled PR because the ADR directory has its own reviewers (often the architecture board or lead engineers) who need to see and approve the deprecation decisions independently of the implementation work. Mixing ADR changes into a large infrastructure PR means the ADR changes receive less scrutiny and are harder to trace from the ADR directory later.
After the mass deprecation PR merges, run the CI supersession integrity check manually against the updated directory to confirm no existing ADRs reference the newly deprecated files in a Superseded-by pointer that now requires updating. A deprecated ADR can still be a valid Superseded-by target — the supersession chain remains intact — but the check will surface any inconsistencies introduced by the deprecation.
How WhyChose fits in
ADR retirement presupposes that the decisions reached the ADR directory in the first place. The harder upstream problem is the decisions that never made it — made in ChatGPT or Claude tabs during the original implementation sprint, never formalized into ADRs, and now impossible to supersede or deprecate because they were never recorded. When a component is eventually removed, the team has no documented rationale to point to: the deprecation Notes entry can say "no replacement ADR" but cannot explain what the original reasoning was.
The WhyChose extractor reads your AI chat exports and surfaces those informally-made decisions: the exchange where the team chose Redis over RabbitMQ, the rationale for PCI network isolation, the trade-off discussion about the webhook retry strategy. Those extracted records — even when they were never promoted to formal ADRs — give the retirement PR something to link to. The deprecation Notes entry can say "original rationale in WhyChose extraction ID wc-2024-03-0034" rather than "no documented reason." Future engineers doing archaeology after the retirement find the reasoning even when nobody wrote an ADR at the time.
Related questions
When should I deprecate an ADR rather than superseding it?
Deprecate when the decision is no longer operative but there is no single named successor ADR to point to. The core test: supersession is for when the Decision section became factually false (a new ADR explicitly reversed the choice); deprecation is for when the Context section became void — the component was removed, the team dissolved, the architectural area migrated away without a direct replacement decision. If you can write a Supersedes: NNNN-old.md line in a new ADR and it makes sense, supersede. If there is no such new ADR and the decision's context has simply dissolved, deprecate.
Can you delete an ADR that was a mistake?
Almost never. The only justified deletion is a Proposed (never-Accepted) ADR whose PR was closed without merging. Once an ADR has been Accepted and used to guide any implementation decision, it is permanently part of the audit trail. Deleting it removes the record that the decision existed — exactly the loss the ADR practice is designed to prevent. An Accepted ADR that was later invalidated should be moved to Superseded or Deprecated, not deleted. Git history will show the deletion regardless, and a reviewer following the supersession chain will hit a dead end.
What can the Deprecated-by field point to?
Deprecated-by can point to any artifact that explains why the decision became irrelevant — a PR number, a commit SHA, a Jira or Linear ticket, a migration guide URL, or another ADR that covers the successor domain at a higher level of abstraction. Unlike Superseded-by, Deprecated-by is not verified by CI for file existence. If no specific artifact explains the deprecation, omit the field and write a plain-text reason in a Notes entry instead.
How do I handle mass deprecation when a component is removed?
Open a single PR touching only the ADRs covering the removed component — no interleaved unrelated changes. Each ADR gets Status: Deprecated and a Notes entry in the format Deprecated YYYY-MM-DD: [component] removed in PR #NNN. No replacement ADR — [brief reason]. The PR description lists all files changed, explains the removal, and links the removal PR. Mass deprecation in one atomic PR keeps the audit trail clean: a reviewer can see exactly which architectural decisions became irrelevant in the same action as the removal.
Further reading
- ADR supersession pattern — when to supersede, when to annotate, and how to stay bidirectional — full protocol for the two-file atomic supersession case: the four triggers, bidirectional pointer maintenance, cascade chains, orphan recovery, and the CI integrity check in detail.
- How to update an ADR (without breaking the audit trail) — the 5-state lifecycle (Proposed → Accepted → Superseded / Deprecated / Rejected), the legal and illegal state transitions, and the Notes-section convention for changes that don't warrant a status change.
- ADR status template — format, fields, and the lifecycle beyond Accepted — Status field placement in both Nygard and MADR formats, the five canonical status values including Deprecated, the CI badge conventions, and the companion fields (date, decision-by, reviewers, trial-until).
- The ADR GitHub Action workflow — the four-job CI workflow; the supersession integrity job (job 3) tests Superseded-by pointers for file existence but does not test Deprecated-by pointers, by design, because Deprecated-by targets are PR URLs and tickets rather than ADR filenames.
- ADR adoption guide — rolling out the practice to a skeptical team — if the team's ADR directory has accumulated mostly stale and undeprecated ADRs, the adoption guide's 60-day threshold and visibility diagnosis applies here: a directory full of Accepted ADRs that describe retired systems is a signal the practice lost momentum, not a reason to delete the files.
- The open-source extractor — surfaces the decisions behind the components you are now retiring, so the original reasoning is findable in git even after the ADRs are deprecated and the component is gone.