API Versioning Strategy: A Fill-In Policy for Your Team
An API versioning strategy answers four questions: what counts as a breaking change, where the version number lives, how long old versions keep working, and how clients hear about changes. Write those four answers down before you ship a second version.
Most versioning pain comes from skipping the first question. Teams argue about URL paths versus headers while quietly making breaking changes in "minor" releases. The outline below is meant to be copied into a one-page internal policy and edited.
Vendors Covered in this Article
Disclosure: We may earn a commission if you buy through some links on this page. It doesn't change what we recommend.
What counts as a breaking change?
Define this in writing, because engineers disagree on the edge cases. A change is breaking if a correct, existing client can stop working without modification. Treat these as breaking:
- Removing or renaming a field, endpoint, or enum value.
- Changing a field's type, format or units, including turning a number into a string.
- Making an optional request field required, or tightening validation.
- Changing the meaning of an existing value or an error code that clients branch on.
- Changing authentication or pagination behavior.
Treat these as safe: adding an optional request field, adding a response field, and adding a new endpoint. That rule only holds if you tell clients to ignore unknown fields, so state it in your docs.
Where should the version live?
Three placements are common, and each has a tradeoff:
- URL path (`/v2/orders`): obvious, easy to route at a gateway, easy to see in logs. Changing a version changes every URL, which some teams dislike.
- Request header or media type: keeps URLs stable and is more purist. It's harder to test in a browser and easy for clients to forget.
- Date-based version header: the client pins a date and gets the behavior from that day. Good for frequent small changes, but you need infrastructure to maintain each behavior snapshot.
For a small team with a public API, the URL path is the pragmatic default. Version the whole API at once rather than per endpoint, so customers have one number to track.
How to write your deprecation policy
Fill in this outline and publish it:
- Announcement: how far ahead you'll notify clients before removal, and through which channels (changelog, email to the account owner, response header).
- Support window: how long the previous version keeps working after the new one is stable. Pick a period you can afford to run two versions.
- Signals: add a Deprecation or Sunset header to old-version responses so clients can detect it in code.
- Usage tracking: log which keys still call the old version so you can contact them directly before shutting it off.
- Shutdown: a date, a final warning, and an agreed exception process for large customers.
Say your window is twelve months. That number matters less than sticking to it. A policy you break once teaches customers to ignore your announcements.
How do you run two versions without doubling the work?
Keep one core implementation and translate at the edge. The new version's logic is the source of truth, and the old version is a thin adapter that reshapes requests and responses. A gateway such as Kong or Apigee can route by version, but the translation logic usually belongs in your code, where tests can reach it.
Avoid copying the whole codebase for v1. That path leads to two sets of bugs. Contract tests that run against both versions on every build catch the drift early.
Which mistakes cause the most client pain?
Watch for these patterns:
- Shipping a breaking change under the same version because "nobody uses that field". Check logs before deciding, and even then, version it.
- Bumping the major version for every small change, so nobody knows what the number means.
- Deprecating with no replacement documented. Every deprecation needs a migration note that shows old call, new call.
- No changelog. A public, dated list of changes is the cheapest way to build trust.
A useful habit is a standard changelog entry: the date, the version affected, what changed, whether it's breaking, and the exact old and new call. Post it where developers already look, and email account owners for anything breaking. Clients forgive change they were told about early and plainly.
Link your versioning rules to how you structure logs, since version and client ID in every request log line make the usage tracking step possible.
What Good Looks Like
A written policy defines breaking changes, states where the version lives and how long old versions run, and the team follows it without exceptions.
Building The Capability (5-Stage Skill Ladder)
How to Get Started
Disclosure: We may earn a commission if you buy through some links on this page. It doesn't change what we recommend.
Frequently Asked Questions
What is the best way to version a REST API?
For most small teams, put a major version in the URL path, such as /v2, and version the whole API together. It's easy to route, log and debug. Header-based versions are valid but harder for clients to discover and test.
How long should you support an old API version?
Long enough for typical customers to plan and ship a migration, and no longer than you can afford to run both. Publish the period in your policy and keep to it. Larger customers may need a documented exception process.
Is adding a field to an API response a breaking change?
Usually not, provided your documentation tells clients to ignore fields they don't recognize. Removing, renaming or changing the type of a field is breaking. State the rule in your docs so client authors write tolerant parsers.
Do internal APIs need versioning?
Often a lighter version. When you control every caller, you can coordinate changes with deploy order and contract tests. Once other teams or external parties depend on an API, treat it like a public one.
About the numbers
This guide doesn't quote a sourced benchmark. Figures in it are estimates or general guidance, so check them against your own numbers.
Related Guides
What Should a Startup Log? A Practical Logging Plan
Decide what to log, how to structure it, what to never record, and how long to keep it, so logs help during incidents without a huge bill.
Cloud Cost Tagging: A Strategy for Splitting Spend by Team and Product
Choose a minimum tag set, enforce it at creation, handle shared costs and track coverage so your cloud bill can be split by team and product.
Postgres Backup Checklist: What to Verify Before You Need It
A Postgres backup checklist covering logical dumps, point-in-time recovery, retention, off-account copies and the restore drill most teams skip.
A Service Catalog for Engineering Teams: Fields, Tiers and Upkeep
The fields every service entry needs, how to define tiers, where to store the data and how to keep a service catalog from going stale.
Kong vs Apigee vs Cloudflare API Shield: API Gateways Compared
Compare Kong, Apigee, and Cloudflare API Shield for API gateway management, edge rate limiting, microservice ingress, mTLS security, and latency.
Rate Limiting an API: Limits, Headers and 429 Errors
How to set API rate limits: choose an algorithm, decide what to limit by, pick first numbers, and return 429 responses clients can handle.