Blog · 2026-06-06 · ~10 min read
When to supersede vs. deprecate an ADR: the decision record lifecycle
In early 2025, a backend team at a 20-person SaaS company migrated their job queue from Redis to a PostgreSQL-backed implementation. They followed the existing ADR: Use Redis for the job queue — lower operational complexity for current team size, avoids a secondary persistent-service dependency. The reasoning was sound. They shipped. Six months later, the engineer who wrote that ADR looked at the PR and said: "We actually superseded that in 2024 when we decided to consolidate onto PostgreSQL to reduce the number of long-lived services we were running. I thought I updated the status but I guess I just wrote a new ADR and never changed the old one." The 2023 ADR was correct when written. The constraint dissolved when the team scaled past fifteen engineers and PostgreSQL was already the primary datastore. Nobody deprecated it. Nobody superseded it. The status still said Accepted.
TL;DR
ADRs have a lifecycle: Proposed → Accepted → Deprecated or Superseded. Supersede when a new explicit decision replaces the old one — link both records to each other. Deprecate when the decision is no longer operative but no specific new decision replaced it — the context changed, the constraint dissolved, or the feature was removed. Never delete; the history has institutional value even when the decision is no longer current. The most common failure mode isn't failing to write ADRs — it's leaving Accepted ADRs that are silently stale. AI chat extraction catches this by surfacing conversations where engineers question existing decisions, giving you both the staleness signal and the date it started.
The ADR lifecycle: four states
The original Nygard format defined the simplest possible lifecycle: Proposed (written, under discussion), Accepted (operative, team agreed), Deprecated (no longer operative, no replacement), and Superseded (replaced by a newer ADR). Later formats — MADR in particular — expanded on this, but the core four states have held up because they describe four meaningfully distinct situations.
Proposed is the pre-decision state. The ADR exists as a write-up of the decision problem and the candidate options, but the team hasn't closed it. Some teams use Proposed as the RFC equivalent — the document is the proposal, comments are the review, and Accepted is the merge. Others write ADRs post-decision and skip Proposed entirely. Either approach works; the important thing is that Proposed means "not yet settled."
Accepted is the operative state. The decision was made, the ADR records it, and the team is acting on it. Most ADRs spend most of their life in this state. The goal of the lifecycle is to ensure that Accepted accurately means "this is what we're doing right now" — not "this is what we decided, but it may or may not still be true."
Deprecated means the decision is no longer operative, but there's no specific new decision that replaced it. The context changed without a deliberate successor. The team stopped using Redis not because they made a "switch from Redis to X" decision, but because they removed the feature that needed a queue. Or the team that owned the domain disbanded and the decision's scope became moot. Or the constraint that justified the decision simply dissolved over time. Deprecated says: "this was the right call, but it no longer applies, and we haven't made a new decision to replace it."
Superseded means a specific new ADR explicitly replaced this one. The superseding ADR made a different decision on the same question. Both records link to each other: the old ADR's status block says "Superseded by ADR-0067," and ADR-0067 says "Supersedes ADR-0031." The chain of custody is preserved. A new engineer can read ADR-0031, see it was superseded, follow the link to ADR-0067, and understand both the original reasoning and why the team changed course.
There is a fifth case worth naming: Deleted. Don't. See the section below.
Supersede: when a new decision explicitly replaces the old one
Supersession is the right status when the team made a deliberate, conscious new decision that directly contradicts or replaces the previous one. The key word is "deliberate" — someone proposed an alternative, the team evaluated it, and they made a new call. That new call has its own ADR. The old ADR is now historical record.
Supersession applies when:
- The technology choice changed — "use PostgreSQL for the job queue" supersedes "use Redis for the job queue"
- The architectural approach changed — "use event sourcing for the order service" supersedes "use a mutable state model for the order service"
- The team made an explicit "we got this wrong" acknowledgment — "authentication via JWT" supersedes "authentication via server-side sessions" after a security review
- The scope of a constraint changed as a result of a deliberate policy update — "require two-person review for production deployments" supersedes "production deployments can be merged by the author"
In each case, there's a new decision that can stand alone as an ADR. The new record names what it's superseding in the status block. The old record is updated to point at its replacement.
The mechanics of writing the link matter for future searchability. In the Nygard template, the status block is a free-text field — write it as: Status: Superseded by ADR-0067 (2025-03-14). In MADR format, the status field is structured YAML: status: superseded by ADR-0067. In either case, the new ADR should carry: supersedes: ADR-0031 or Supersedes: [ADR-0031 Use Redis for the job queue](./0031-redis-job-queue.md). Both records should be updated. A supersession trail that runs only one direction is worse than useless — it creates the impression of resolution where there is only partial accounting.
Deprecate: when the context dissolved without a named replacement
Deprecation is the right status when the ADR is no longer operative, but there's no specific new decision that replaced it. The distinction from supersession is subtle but important: deprecation says "the question this ADR answered is no longer a live question for this team," not "the question is still live and we've now answered it differently."
Deprecation applies when:
- The feature or service was removed — the ADR about the job queue becomes moot when the product drops async processing entirely. No new decision replaces it; the question just stopped existing.
- The constraint that motivated the decision dissolved — the ADR said "use SQLite because the team is two engineers and can't manage a separate database service." The team is now twelve engineers with a dedicated infrastructure person. No new "switch from SQLite" decision was made — the product grew out of the constraint without a deliberate switchover.
- The team structure changed so the decision's scope is no longer meaningful — a decision about how the mobile team handles push notification tokens becomes moot when the company discontinues the mobile app. There's no "mobile app discontinuation ADR" — it was a business decision, not an architecture one, and the ADR about push tokens is now just historical record.
- The technology it references was removed from the ecosystem — a decision about how to handle Internet Explorer CSS compatibility is deprecated not by a new browser-compatibility decision, but by IE's end-of-life. The question stopped mattering to the team.
Write the deprecation with a one-line note explaining why: Status: Deprecated (2025-09-01) — async job processing removed from the product in the v3.0 rebuild; this constraint no longer applies. The note is load-bearing. Without it, the deprecation looks like an oversight rather than a deliberate cleanup. Future engineers reading the ADR history should be able to understand not just that the decision was retired, but why it became moot.
A common mistake is to write Superseded by nothing or Superseded — no replacement. That's not what superseded means. If there's no specific replacement ADR, the right status is Deprecated. Superseded implies a chain of custody. Deprecated implies a clean ending.
The silent-stale failure mode
The scenario in the opening of this post — the Redis ADR that said Accepted long after the team had moved on — is more common than either supersession or deprecation failures, because it doesn't require any action at all. It just requires no action. The old ADR stays Accepted because nobody thought to update it. The team moved on, made new decisions, and the old record became a ghost in the codebase.
This failure mode is worse than a correctly-deprecated or correctly-superseded ADR, because it's invisible. An engineer who finds a Deprecated or Superseded record knows to look for more context. An engineer who finds an Accepted record assumes it's current. The silent-stale case actively misleads.
It's also the hardest failure mode to catch with tooling. A GitHub Action that validates ADR status can check that every record has a status field and that status values are from an allowed set. It cannot check whether an Accepted ADR reflects the current state of the codebase — that requires reading the code and reading the ADR and comparing them, which is human work.
The worked ADR example at the WhyChose reference library uses the Postgres-vs-MongoDB scenario precisely because it's a technology choice that teams revisit as they scale — the decision correct at ten engineers is often wrong at fifty. The example is structured to make the context explicit (team size, operational maturity, existing expertise) so that a reader can evaluate whether the context still holds, even without a status update. That's one mitigation for silent-stale: write ADRs with enough context that future engineers can assess their own validity rather than having to take the status field on faith.
The other mitigation is the quarterly review. The quarterly triage workflow includes an obsolescence check on the second pass — by the time you've done a second quarterly review, you have an existing log to compare against. During that pass, you check whether any extracted conversations from the last quarter reference existing ADRs in a questioning frame. That's a staleness signal worth acting on immediately.
What AI chat extraction reveals about decision half-lives
One of the less-obvious outputs of running the WhyChose extractor on a multi-year chat history is a proxy measure for decision half-lives. When engineers start questioning a past decision, they usually work through that questioning in AI chat — the same surface where they made the original decision. The extractor surfaces these conversations as new decision candidates, because the questioning conversation has the same structure as the original decision conversation: a constraint is named, alternatives are weighed, a direction emerges.
From the 1,200-chats extraction walkthrough, the data broke down roughly like this by decision category:
- Technology choices (library selection, service choice, language for a new service): median time to first "should we revisit this?" conversation was around eight months. These are the decisions most often disrupted by ecosystem changes — a library releases a major version, a competing service drops its price, a security audit reveals a dependency gap.
- Process and workflow decisions (code review policy, deployment cadence, meeting format): median time to first questioning was around four months. These are the decisions most sensitive to team composition changes — a new engineer joins who has strong opinions about review process, or a team that's grown past a threshold where the old cadence doesn't work.
- Architectural invariants (client-side-only model, database schema conventions, authentication model): no meaningful questioning in eighteen months of history. These decisions have long half-lives because they're structurally load-bearing — changing them isn't just a new decision, it's a product redesign. Teams don't question them casually.
The practical implication for ADR lifecycle management: if you're writing a technology-choice ADR, set a calendar reminder for eight months out to run an obsolescence check. The reminder isn't a promise to supersede it — it's a prompt to check whether the context that justified the choice still holds. If it does, reaffirm explicitly (a note on the record, a date of last-review). If it doesn't, start the supersession process.
The chat-extraction approach surfaces these signals automatically. During the quarterly triage pass, any extracted decision conversation that references an existing ADR — "we decided last year to use Redis, but I'm wondering if that makes sense now that Postgres is already our primary database" — is both a new candidate and a staleness flag on the old ADR. The conversation date tells you when the questioning started. Compare that date to the ADR's written date: if the gap is under six months, the original decision may have been under-specified. If the gap is over eighteen months, the decision held up well before being questioned. In both cases, you now have the data to make the supersession or deprecation call deliberately rather than reactively.
How to write the status block correctly
Most ADR staleness problems aren't failures of intent — teams know when they've changed course. They're failures of execution: the new ADR gets written, the old one's status never gets updated, and the link never gets added. The update is low-effort but easy to forget. Here's a concrete before-and-after for the Redis example.
Before (silent-stale):
# ADR-0031: Use Redis for the job queue
Date: 2023-08-15
Status: Accepted
## Context
The team is eight engineers. We need an async job queue for email delivery
and report generation. Adding a separate persistent service (Postgres) has
operational overhead we don't currently have capacity to manage well.
## Decision
Use Redis as the job queue backend (via BullMQ).
## Consequences
Redis adds one more persistent service to operate. At current team size,
BullMQ's operational simplicity and Redis's battle-tested queue semantics
outweigh the added service. Revisit when team has dedicated infrastructure
capacity or when Postgres is already deployed for another purpose.
After (correctly superseded):
# ADR-0031: Use Redis for the job queue
Date: 2023-08-15
Status: Superseded by ADR-0067 (2025-03-14) — team scaled past 15 engineers,
PostgreSQL was already the primary datastore; consolidating onto a single
persistent service was the right call. See ADR-0067.
## Context
[unchanged]
## Decision
[unchanged]
## Consequences
[unchanged]
And ADR-0067:
# ADR-0067: Move job queue from Redis to PostgreSQL (pg-boss)
Date: 2025-03-14
Status: Accepted
Supersedes: ADR-0031 (Use Redis for the job queue)
## Context
Team has grown to 18 engineers. PostgreSQL is the primary datastore
for all product data. We are running Redis solely for the job queue.
Operating two separate persistent services adds infrastructure complexity
with no remaining benefit — the original ADR-0031 context (team too small
to manage two databases) no longer holds.
## Decision
Migrate the job queue from Redis/BullMQ to PostgreSQL/pg-boss.
Decommission the Redis instance after migration is confirmed stable.
## Consequences
Reduces the persistent-service count from two to one. pg-boss provides
comparable reliability and observability to BullMQ at this scale.
Migration window estimated at one sprint; rollback path is Redis restore
from backup if pg-boss proves unstable in production.
Notice what the update does: it keeps the original ADR completely intact. The decision text, the context, the consequences — none of it changes. The only addition is a status line that says when it was superseded and why, plus a link to the replacement. A new engineer reading ADR-0031 can't be misled by it because the status line immediately redirects them. A new engineer reading ADR-0067 can see what it replaced and why, giving them the full decision history in one read.
The How to document architecture decisions reference page covers the 3+1 rule for ADR fields — the three required sections (Context, Decision, Consequences) plus the optional fourth (Alternatives Considered). Status management fits in the required metadata block, not in any of the four sections. It should never need more than two lines.
Why you should never delete an ADR
The instinct to delete a stale ADR is understandable: the decision is wrong, the record is misleading, removing it feels like cleanup. But deletion destroys institutional memory in ways that take years to manifest and are invisible when they do.
An ADR that was superseded tells future engineers that the team considered and rejected the old approach. That information has value independently of whether the new approach is still current. Without the superseded ADR, a new engineer who proposes the old approach doesn't know whether the team has ever considered it, whether there were good reasons to reject it, or whether the current approach was chosen for reasons that still apply. The deleted ADR's absence creates exactly the conditions for re-litigation — the same problem that "not building this" decision records exist to prevent.
Consider a team that, in 2022, evaluated event sourcing for their order service and decided against it — the operational complexity at their current scale wasn't worth the auditability benefits. They wrote an ADR. In 2024, they migrated to a CQRS-adjacent pattern that addressed some of the same concerns in a simpler way. The 2022 ADR was superseded. But the reasoning in the 2022 ADR — why event sourcing specifically was rejected, what alternatives were considered, what the specific cost-benefit analysis looked like — is still valuable in 2026 when a new staff engineer joins and wonders why the team didn't use event sourcing. The superseded ADR is the answer. Delete it, and you're back to "we looked at that" with no supporting detail.
The other reason not to delete: git history is not a substitute. Deleted files in git history are technically recoverable, but in practice they're inaccessible — most engineers don't know to look for them, don't know the filename to search for, and don't have the context to find the right commit. If the ADR is worth keeping at all (and it is), keep it in the working tree with an updated status. The file system is the interface; git history is the backup.
Finding stale ADRs in the quarterly triage pass
The quarterly decision review workflow mentions an obsolescence check during the second quarterly review — once you have an existing log, you can scan it for records the current quarter's extraction calls into question. Here's how that check works in practice.
During the quarterly triage pass, after sorting extracted decisions into Promote / Link / Park / Dismiss buckets, scan the "Link" bucket specifically. The Link category — decisions that reference an existing decision rather than being new standalone decisions — is where staleness signals concentrate. A conversation that says "I've been thinking about our Redis queue choice — now that we're already running Postgres everywhere, does it still make sense?" is a Link candidate, not a Promote candidate. It's not a new standalone decision; it's questioning an existing one. But it's a strong signal that ADR-0031 needs an obsolescence check.
For each Link-category extraction that references an existing ADR:
- Find the existing ADR in the decision log
- Check whether the context section still accurately describes the current situation
- If the context has changed and the decision would now be made differently: begin the supersession process — write ADR-0067, update ADR-0031's status
- If the context has changed but the decision still holds (the team's now bigger but Redis is still the right call for other reasons): add a "reaffirmed" line to the status block with the date and the new reasoning. This is an underused pattern — reaffirmation says "we reconsidered this and still agree," which is its own kind of institutional memory.
- If the context has dissolved (the feature that needed the queue was removed): deprecate the ADR with a note explaining why
The extracted conversation date is the anchor: it tells you when the team started questioning the decision. If the gap between the original ADR date and the first questioning conversation is consistent with the decision category's typical half-life (eight months for technology choices, four months for process decisions), the staleness is expected and manageable. If the questioning started much earlier — within weeks of the original decision — it may indicate the original decision was under-specified or the context was miscaptured in the ADR.
Run the WhyChose extractor on your ChatGPT export or Claude export and the Link-category conversations become visible. Without extraction, this signal lives in unindexed chat history and the quarterly check requires manually reading every conversation from the last quarter. With extraction, the signal surfaces automatically in the triage output.
Run the extractor quarterly and watch the Link category for staleness signals. The open-source WhyChose extractor surfaces both new decisions and "questioning an existing decision" conversations from your ChatGPT or Claude history. MIT-licensed, runs locally, nothing sent to a server. During the triage pass, Link-category extractions that reference existing ADRs are supersession or deprecation candidates. Update the status blocks immediately — the five minutes it takes is worth more than any amount of post-hoc archaeology when a new engineer ships based on a ghost ADR. Join the waitlist for the hosted version with team sharing, Notion and Linear export, and search across all quarters.
Related questions
What's the difference between superseding and deprecating an ADR?
Superseding means a new ADR explicitly replaces the old one — a new decision was made that directly contradicts or replaces the previous one, and both records link to each other. Deprecating means the old ADR is no longer operative, but no specific new decision replaced it — the context changed, the constraint dissolved, or the feature was removed without a successor decision being made. Use Superseded when there's a named replacement. Use Deprecated when the old decision just stopped being relevant without a new one taking its place.
Should I delete an ADR that's no longer current?
No. Even an outdated ADR has institutional memory value — it records what was decided, the reasoning behind it, and the context that made it correct at the time. Future engineers (and your future self) benefit from knowing that a constraint was operative, even if it's no longer active. Deleting removes that history. Instead, update the status to Deprecated or Superseded, add a brief note explaining why the decision is no longer operative, and link to any successor. The ADR becomes a historical record, not a current directive, but the history is still worth keeping.
How do I know when an ADR needs to be superseded rather than just edited?
Edit the existing ADR only for minor corrections — typos, clarifications, broken links. If the decision itself changed — if what the team is now doing is different from what the ADR says — create a new ADR and supersede the old one. The rule of thumb: if a new engineer reading the ADR would make a different architectural choice than the team actually made, that's a supersession event, not an edit. ADRs are meant to be immutable records of decisions made at a point in time. Editing the decision retroactively destroys the audit trail. Create a new record; link the old one to it.
Can AI chat extraction help me find ADRs that have gone stale?
Yes, indirectly. When engineers start questioning a past decision, they usually work through that questioning in AI chat — "we decided last year to use Redis for the queue; I'm wondering if that still makes sense now that we're already running Postgres everywhere." The WhyChose extractor surfaces these conversations as new decision candidates, because the questioning conversation has the same structure as the original decision conversation: a constraint is named, alternatives are weighed, a direction emerges. During the quarterly triage pass, any extracted decision that references an existing ADR by context is a staleness signal. The extracted conversation dates tell you when the questioning started — and the gap between the original ADR date and the first questioning conversation is a proxy for that decision's half-life.
Further reading
- The open-source WhyChose extractor — runs locally on your ChatGPT or Claude export, MIT-licensed, no signup required. The quarterly triage output is where staleness signals concentrate.
- The quarterly decision review: a 30-minute ritual — the full triage workflow; covers the Promote / Link / Park / Dismiss buckets and the second-quarterly-review obsolescence check in detail.
- Decisions that never get written down: the "not building this" record type — the deferred-vs-permanent distinction in "no" decisions maps directly onto the deprecate-vs-supersede question for records that become moot.
- ADR vs Decision Log vs RFC: when to use each — the artifact disambiguation that sets the context for lifecycle management; if you're not clear on when a decision warrants a full ADR, lifecycle management is harder.
- Why your team's ADRs go stale after 60 days — the round-trip cost analysis; silent-stale ADRs are a downstream consequence of the same practice failures that kill ADR adoption at 60 days.
- The MADR 4.0 spec in 15 minutes — MADR's formal
statusfield with structured YAML semantics; the spec has explicit support forsuperseded byandsupersedesin the frontmatter. - From 1,200 ChatGPT chats to 38 durable decisions — the source for the decision half-life data; technology choices, process decisions, and architectural invariants each have characteristic half-lives in the extraction data.
- Worked ADR example (Postgres vs MongoDB) — the full Nygard-format example with context, alternatives, and consequences sections; illustrates how to write the context block in a way that makes future obsolescence checks self-guided.
- Nygard ADR template — the original five-section format; the status field is the lifecycle anchor; this page covers how to write status values and links.
- How to document architecture decisions — the 3+1 rule; covers what belongs in the ADR vs. what belongs in the PR description or commit message.