How to write a deprecation policy (with template)

A deprecation policy is a promise you publish before you need it: when we retire something you depend on, here is how much warning you get, where you will hear about it, and what happens to the old thing in the meantime. For anything people build on — an API, an SDK, a CLI, a file format — it is one of the highest-leverage documents you can ship, because it converts every future removal argument from “is this fair?” into “did they follow their policy?” This guide covers what goes in one, how to pick notice windows you can actually honor, and ends with a copy-paste template.

Why you write it before you need it

A policy written in the middle of a controversial removal reads as damage control, because it is. The same words published a year earlier read as a commitment, because they were. The whole value of the document is that it predates any specific decision — nobody can accuse you of writing the rules to excuse the thing you already did.

It also disciplines you. Without published windows, “nobody uses this endpoint, just remove it” wins arguments on mood. With them, removal has a checklist: announce, tag, set the sunset date, notify the accounts still calling it, wait out the clock. The policy is as much a leash on your own roadmap impatience as it is a shield for users.

And it compounds commercially: teams evaluating a platform dependency increasingly ask for exactly this document — procurement checklists literally include it. A public deprecation policy is a trust asset you write once.

First, define what “deprecated” means

The word does different work at different companies, and users know it. Your policy's first job is an operational definition. People holding a deprecated thing have three questions: does it still work? will it get fixes? when does it stop? A definition worth publishing:

  • It keeps working until its published sunset date — deprecation is a clock, not a breakage.
  • It keeps getting security and critical fixes, but no new functionality.
  • It will not be removed before the sunset date. Ever.

If deprecated things in your product quietly degrade or break before their date, your policy is fiction and everyone who hit the breakage knows it. The definition only counts if operations match it.

The five things the policy must cover

  • Scope. Which surfaces the promise covers: the documented HTTP API, official SDKs, CLI commands and flags, webhook payloads, config formats. And — just as important — what it explicitly does not: undocumented endpoints, response fields that never appeared in the docs, internals, and anything labeled beta or experimental (give those their own, shorter rule). Vague scope means every future incident becomes a scope debate.
  • Notice windows. The minimum time between announcement and removal, per class of surface. This is the number people quote back to you, so it gets its own section below.
  • Channels. The specific places a deprecation will be announced — a changelog people can subscribe to by feed, in-band signals like response headers, direct email for the accounts actually affected. A channel promise is only real if it is subscribable in advance.
  • The operational definition of deprecated, from above.
  • Exceptions. A security hole or a legal requirement can force a faster change. Say so up front, and promise as much notice as circumstances allow plus an explanation of why the normal window didn't apply. An exception clause you wrote in calm weather is credible; one invented mid-incident is not.

Picking windows you can honor

Tie the window to the consumer's migration effort, not to your roadmap appetite. Someone with your API call sites spread across a codebase, a deploy train, and a compliance review needs quarters; someone clicking a different button in your UI needs weeks. Reasonable starting points:

  • Documented API endpoints, fields, webhook payloads: 6–12 months. Programs don't adapt on their own, and the person who wired the integration may be two jobs away. (See API changelogs for why API surfaces are the unforgiving case.)
  • CLI commands and flags: 6 months. They live in scripts and CI nobody re-reads until they break.
  • Product features in the UI: 30–90 days. Humans adapt faster than programs, but they still deserve a date, a replacement, and a chance to export.
  • Libraries are the exception to date-based windows: consumers pin versions, so “deprecated in one major, removed in the next” works — that's what semver majors are for. For anything hosted, use calendar dates: nobody can pin your SaaS (CalVer vs SemVer covers this split).

Two rules make the numbers durable. Pick one window per class, not per argument — few, round, memorable numbers beat a bespoke negotiation each time. And commit that dates may move later, never earlier. A modest window kept every time builds more trust than a generous one broken once.

The deprecation lifecycle (and its in-band signals)

A policy describes a repeatable sequence. The one that works:

  • Announcement. A dated changelog entry with the sunset date, the replacement, and the migration path — the breaking-changes guide covers writing that entry. This entry's URL becomes the canonical reference for everything that follows.
  • Reminders. At least one at the midpoint and one shortly before sunset. Schedule them the day you announce — don't trust future-you's memory.
  • In-band signals for the whole window. Announcements are missable; signals inside the deprecated thing are not. HTTP APIs have standard Deprecation and Sunset headers (RFC 8594) that can link to your announcement; SDKs and CLIs can print one-line warnings; docs pages for the old thing get a banner pointing at the replacement.
  • Sunset. Removal day gets its own changelog entry linking back to the original announcement — proof the process ran end to end.

Alongside the policy, keep a public table of live deprecations: what, announced when, sunset date, replacement link. A tag-filtered changelog view does this for free. The table is your policy made visible — and the first place support links when someone asks “is X going away?”

A copy-paste template

Numbers and surfaces below are placeholders — replace them with ones you will actually honor, then publish it somewhere linkable:

# Deprecation policy

Scope. This policy covers our documented HTTP API, official
SDKs, CLI commands and flags, and webhook payloads. It does not
cover undocumented endpoints, response fields absent from the
docs, or anything labeled beta (see below).

What "deprecated" means. A deprecated feature keeps working and
keeps receiving security fixes until its sunset date. It gets no
new functionality. We never remove it before the sunset date.

Notice. We announce deprecations at least this long before
removal:
  - API endpoints, fields, webhook payloads: 12 months
  - CLI commands and flags: 6 months
  - Product features: 90 days
Sunset dates may move later, never earlier.

Where we announce. Every deprecation appears in our changelog
(<url>) tagged "announcement", with the sunset date and a
migration path. Responses from deprecated API endpoints include
Deprecation and Sunset headers linking to the announcement.
Accounts that used a deprecated endpoint in the previous 90 days
receive a direct email.

Beta. Anything labeled beta or experimental may change or be
removed with 30 days' notice.

Exceptions. If a security issue or legal requirement forces a
faster change, we will give as much notice as circumstances
allow and explain why the normal window did not apply.

Current deprecations: <link to your tag-filtered changelog>

Keeping the promise

  • Link the policy from every announcement, and link every removal entry back to its original announcement. This mesh of stable URLs is what makes the process auditable — which is the point.
  • Schedule the reminders at announcement time. The midpoint reminder that depends on someone remembering it does not happen.
  • Measure before you remove. The week before sunset, look at who is still calling the old thing and email them directly. The goal of the entire apparatus is that removal day surprises nobody — zero affected accounts is an achievable target, not a fantasy.

Anti-patterns

  • “We may change anything at any time.” That's a disclaimer, not a policy. It buys legal cover you mostly had anyway and forfeits every gram of the trust a real policy earns.
  • Windows in version numbers for hosted products. “Removed in v3” is meaningless to someone who can't pin v2. Versions work for libraries; dates for everything hosted.
  • Deprecation by silence. Docs quietly deleted, feature removed, no entry ever posted — the removal itself becomes the announcement, experienced as an outage.
  • The unfindable policy. Buried in a terms-of-service PDF, it might as well not exist. Give it a URL, link it from the docs and from every announcement.
  • Shortening a window once. One moved-earlier date converts every future sunset date into a “maybe” — you keep the ceremony and lose the benefit.
  • Policy maximalism. Promising 24 months on everything because it sounds generous, then breaking it. The promise you keep beats the promise that impresses.

Where Wakelog fits

The lifecycle above is mostly a changelog workflow, and Wakelog covers it without a paid tier: entries get permanent URLs your Deprecation and Sunset headers can point at; the announcement tag plus a tag-filtered public page gives you the live-deprecations table for free; scheduled publishing lets you write the midpoint and final reminders the same day you announce; and RSS, JSON Feed, and webhook mirrors to Discord or Slack make your announcement channel genuinely subscribable — the property the whole policy leans on.

Start your free changelog   Next: announcing breaking changes →

Related guides

Last updated 2026-07-27 · All guides