Tags: web-dev concept

Deprecation

Date: 2026-08-17


Removing something people depend on, on a published timetable, with somewhere for them to go. The engineering is trivial; the whole difficulty is that announcement doesn’t cause migration, so a deprecation without measurement of actual usage is a guess about when it’s safe to delete.


Deprecation is formally marking a feature, endpoint or API as scheduled for removal, with a replacement and a date, before removing it.

The sequence

1  DECIDE       what replaces it, and confirm the replacement is genuinely
                sufficient. deprecating with no migration path is just breaking it

2  ANNOUNCE     changelog, email, docs marked, and a date. name the date
                on day one — "sometime next year" is not a deprecation

3  SIGNAL       in the product itself, where the developer already is:
                  · a Deprecation / Sunset HTTP header on every response
                  · a warning in the SDK, once per process, not per call
                  · a console warning naming the replacement
                  · the docs page marked, with the alternative linked

4  MEASURE      usage per consumer. this is the step that's skipped and
                the only one that tells you whether any of the above worked

5  CHASE        contact the remaining callers directly. by now it's a
                short list, and it's the only thing that reliably works

6  BROWNOUT     short scheduled outages before the real one

7  REMOVE       on the announced date

Steps 4 and 5 are where deprecations succeed or fail. Everything before them is broadcast, and broadcast does not move people who have working code and other priorities.

Measurement is the whole game

Without per-consumer usage you have two bad options: delete and find out, or never delete.

endpoint  GET /v1/orders          deprecated 2026-02-01, removal 2026-08-01

          calls/day   consumers   note
2026-02     412,000        38
2026-04     180,000        31     announcement moved the easy ones
2026-06      94,000        22     ← plateau. broadcast has done its work
2026-07      91,000        21       chase these 21 by name
2026-07-20    2,100         3     ← after direct contact
2026-07-28        0         0

The plateau at step 4 is the normal shape, and it’s the signal to switch from announcing to phoning. Log the consumer identity — API key, client ID, user agent — on every call to a deprecated thing, or step 5 is impossible.

Brownouts

Short, scheduled, announced outages of the deprecated thing before it’s removed for good — say an hour, then a day, in the final weeks.

They work because a team that hasn’t migrated usually doesn’t know they haven’t. The dependency is in a service nobody’s touched for a year, and the first genuine signal is a failure in an environment they’re watching. A brownout produces that signal at a time you chose, rather than on removal day.

Announce each one specifically. An unannounced brownout is an outage.

How long

Proportional to who’s affected and how much work it is:

ConsumersReasonable notice
Your own team, internal callDays
Another team in the same organisationWeeks to a quarter
External developers, small changeOne or two quarters
External developers, real migration workA year, sometimes more
Anything customers integrated with a contractWhatever the contract says — check before announcing

Never shorten an announced date. Extending is a courtesy; shortening destroys the credibility of every future deprecation you announce, and credibility is the thing that makes the next one cheaper.

The exception is security. A vulnerable endpoint gets removed on a security timetable, and that is a different communication, sent differently.

What makes it possible at all

  • Version and date things from the start. Retrofitting a deprecation process onto an API with no versioning means the first removal is a breaking change — API Design, Backwards Compatibility
  • Know who your consumers are. Authenticated API keys make this trivial; anonymous public endpoints make it impossible, which is an argument for authenticating even free endpoints
  • A single changelog people actually read, in one place, permanently
  • Deprecate in the type system where you can. A @deprecated annotation surfaces in the editor of everyone using it, which reaches people no email does — Static Analysis

Where it interacts

  • The Strangler Pattern — a strangler migration ends in a deprecation, and the decommission date is the thing that keeps it from stalling
  • Technical Debt — removing a feature is often cheaper than maintaining it, and deprecation is the mechanism. Features nobody uses are still debt
  • Composable Commerce and Integration Patterns — you’re on the receiving end far more often than the sending end, so track vendors’ deprecation notices as work rather than as newsletters
  • Dependency Management — the same process arriving from upstream, on their timetable rather than yours