Skip to content
Back to Maintenance & LTS

Deprecation Policy

Define how, when, and why you deprecate — the rules that make retirement predictable for users.

Why

Without a stated policy, deprecation is ad-hoc: a feature is removed in a minor because someone felt like it, and a client breaks. A policy makes deprecation a contract: deprecated features get a minimum support window (e.g., 6 months), a programmatic signal (Deprecation header / log warning), a documented replacement, and a sunset date communicated in advance. This lets clients plan migrations instead of being ambushed, and it lets your team remove code without guilt because the policy was followed. The policy also prevents the opposite failure — keeping dead features forever because nobody wants to be the one to remove them — by making removal a scheduled, policy-driven event, not a personal decision.

When

Write the policy once before your first deprecation. Apply it to every feature/API you plan to retire.

How

1. Define the support window: minimum 6 months from deprecation to removal (12 for major APIs)
2. Define the signals: Deprecation HTTP header, console.warn in SDK, @deprecated JSDoc, changelog entry
3. Define the documentation: every deprecation must name the replacement and link a migration guide
4. Define the communication: changelog + email to registered users + a deprecation dashboard
5. Define the removal criteria: removal only after (a) sunset date passed AND (b) usage <1% for 30 days
6. Write the policy in DEPRECATION.md and link it from the README
7. Track deprecations in a dashboard: feature, deprecated date, sunset date, current usage %

Example

# DEPRECATION.md (lives in repo root)
## Policy
- Support window: 6 months (minor APIs), 12 months (major APIs)
- Signals: Deprecation header + console.warn + @deprecated JSDoc
- Removal criteria: sunset date passed AND usage <1% for 30 days

# Deprecation dashboard (tracked per release)
| Feature        | Deprecated | Sunset     | Usage | Status   |
|----------------|------------|------------|-------|----------|
| /v1/orders     | 2024-06-01 | 2024-12-31 | 0.3%  | removable |
| legacyAuth()   | 2024-08-15 | 2025-02-15 | 5.2%  | watching  |
| oldExportFmt   | 2024-09-01 | 2025-03-01 | 12%   | notify    |

# Code signal
/** @deprecated use newAuth() instead — removed 2025-02-15 */
export function legacyAuth() {
  console.warn('[deprecated] legacyAuth() will be removed 2025-02-15. Use newAuth().');
  return newAuth();
}

Common Problems

  • ⚠No support window — a feature is deprecated and removed in the same release, breaking clients with no migration time.
  • ⚠Deprecating without naming a replacement — clients are told to stop using X but not what to use instead.
  • ⚠Removing based on the sunset date alone while usage is still 20% — you break real users who didn't see the notice.

Best Practices

  • ✓Require both a sunset date AND usage <1% for 30 days before removal — the date alone breaks laggard clients.
  • ✓Every deprecation must name its replacement and link a migration guide — "don't use X" without "use Y" is useless.
  • ✓Track a deprecation dashboard with usage % per feature — visibility prevents premature removal and identifies forgotten migrations.