Prompt
How do I version and deprecate APIs without breaking clients?
Latest observation
Oct 5, 2026
OpenAI APIWeb search: off
A good rule is: treat API changes as a compatibility problem first, a versioning problem second.
Core principles
-
Prefer additive changes
- Add fields, endpoints, headers, or optional parameters.
- Avoid removing or changing meaning of existing behavior.
-
Keep old behavior working for a long time
- Clients break when they’re forced to move too quickly.
- Deprecation should mean “discouraged,” not “dead today.”
-
Make compatibility explicit
- Document what’s guaranteed: fields, status codes, ordering, nullability, pagination behavior, etc.
- If you can’t guarantee it, version it.
Common versioning strategies
1) URI versioning
Example:
/v1/users/v2/users
Pros
- Easy to understand and route.
- Clear separation between major changes.
Cons
- Encourages “big bang” versioning.
- Can lead to maintaining many versions.
Use when
- You need a clearly incompatible new contract.
2) Header-based versioning
Example:
Accept: application/vnd.myapi.v2+json- or
X-API-Version: 2
Pros
- Cleaner URLs.
- Better for content negotiation.
Cons
- Harder to debug and test.
- Less obvious to consumers.
Use when
- You want versioning to be part of API negotiation rather than the path.
3) Media type / representation versioning
Example:
Accept: application/json; version=2
Pros
- Very REST-friendly.
- Distinguishes resource identity from representation.
Cons
- More complexity in clients and docs.
Use when
- You want strong separation between resource and format evolution.
Best practice: use semantic versioning for the API contract
A practical approach:
- Major version: breaking changes
- Minor version: backward-compatible additions
- Patch: fixes that don’t change contract
Example:
v1.4.2
If you expose only major versions in the endpoint, keep the internal contract versioned in docs/changelog.
How to deprecate safely
Step 1: Announce early
Provide:
- What is deprecated
- Why
- Replacement
- Timeline
- Any migration steps
Step 2: Mark it in the API
Use multiple signals:
- Docs
- Changelog
- Response headers, e.g.:
Deprecation: trueSunset: Wed, 31 Dec 2025 23:59:59 GMTLink: <https://docs.example.com/migrate>; rel="deprecation"
Step 3: Measure usage
Track:
- Which clients call deprecated endpoints
- Frequency
- Last seen timestamps
- Which versions are still active
Step 4: Support migration
Offer:
- Parallel endpoints
- Compatibility shims
- Mapping examples
- SDK updates
- Automated migration helpers if possible
Step 5: Remove only after the sunset date
And only if:
- Usage is low or zero
- You’ve communicated repeatedly
- You’ve provided a fallback path
What changes are safe vs unsafe
Usually safe
- Adding optional fields
- Adding new endpoints
- Adding enum values if clients can ignore unknowns
- Adding query params with defaults
- Expanding response data
Usually breaking
- Removing fields
- Renaming fields
- Changing field types
- Making optional fields required
- Changing default behavior
- Changing status codes in a way clients depend on
- Tightening validation unexpectedly
Design for forward compatibility
To reduce future breakage:
- Clients should ignore unknown fields
- Servers should tolerate unknown optional inputs where possible
- Use stable identifiers, not human-readable labels, in integrations
- Avoid overloading a field with multiple meanings
- Make pagination and sorting explicit
- Treat enums carefully; allow unknown values
Recommended approach in practice
If you’re building a public API:
- Start with a stable v1
- Only make additive changes in v1
- Introduce v2 only for breaking changes
- Run v1 and v2 in parallel
- Deprecate v1 with headers + docs + email/changelog
- Remove v1 after a published sunset and migration window
Example deprecation policy
- Non-breaking changes: anytime
- Breaking changes: new major version only
- Deprecation notice: 6–12 months before removal
- Critical security fixes: may require faster changes, but communicate clearly
Rule of thumb
If an existing client could fail, misbehave, or silently get wrong results, treat it as a breaking change and introduce a new version.
If you want, I can also give you:
- a sample deprecation policy
- a versioning strategy for REST vs GraphQL
- or a concrete migration checklist for your API.