Chapter 05 of 12
When API Versioning Does Not Matter
The situations where a version number buys nothing, what running parallel versions really costs, and the alternatives that solve the same problem for less.
Most writing about API versioning assumes that versioning is the goal and the only open question is which scheme to use. That assumption is wrong often enough to be worth a chapter, because a version number is a permanent liability and it should be taken on deliberately.
Where a version buys nothing
Consumers you can reach. If every caller is a team in your organisation, a breaking change is a coordination problem and not a contract problem. You change the interface, you change the callers, and both ship together. A version number here adds a support burden and prevents nothing.
An API that has not promised anything yet. Before the first stability commitment, the honest state is that everything may change. Semantic versioning has a name for it, since anything below 1.0.0 carries no promise. Say so loudly, keep the audience small, and do not pretend to a stability you have not decided on.
Genuinely additive change. Adding an optional parameter, a response field or an enum value leaves every existing caller working. Cutting a version for it splits your consumers across two contracts that behave identically, and now you maintain both.
Internal platform interfaces behind a single client. A backend built for one application in the same repository has one consumer that ships with it. The contract is real, and the versioning ceremony around it is not.
What parallel versions actually cost
The version cut is cheap, and it is not the expense. The expense is everything that has to exist twice for as long as both versions live.
| Area | What a second live version adds |
|---|---|
| Runtime | Two code paths, or a translation layer, and both in every incident |
| Tests | A second suite that has to keep passing against behaviour you no longer develop |
| Documentation | A second set of pages, examples and changelogs that stay accurate |
| Mocks | A second mock for client teams, matching the older contract |
| Monitoring | A second set of checks, because an outage on the old version is still an outage |
| Support | Every question starts with which version the caller is on |
| Product | New features are built twice, or held back until the old version dies |
None of these is dramatic on its own, and together they are why teams that version casually end up with four live majors and no appetite to remove any of them. The cost does not scale with the number of versions you cut, it scales with the number you keep, multiplied by the years you keep them.
The alternatives worth trying first
Additive change with tolerant readers. The default answer, covered in backward compatible change. Grow the payload, never reshape it, and document that consumers must ignore what they do not recognise.
Feature flags on the consumer. When one integration needs new behaviour and the others do not, a per-consumer flag delivers it without a new contract. This works well for a known set of callers and badly for an open one, because a flag nobody can see is a hidden version.
Expand and contract. Ship the new field alongside the old one, populate both, mark the old one deprecated, and remove it when usage reaches zero. It converts one breaking change into two compatible ones separated by time, which is the whole trick.
Consumer-driven contracts. When each consumer states what it depends on, you can answer the question of who breaks before you decide anything. Quite often the answer turns out to be nobody, or one team you can message.
What you still need without versions
Not versioning is not the same as not being careful, and the discipline that replaces the version number is where the value sits.
You still need the classification, because knowing that a change is breaking is what starts every other conversation. You still need a changelog, since an unversioned API that changes silently is worse than a versioned one. You still need a way to detect that a change escaped, which means checking real responses against the written contract rather than trusting that additive was actually additive.
That last one is the load-bearing part. Additive evolution is a claim about what your service does, and a claim nobody verifies decays quietly.
The honest downside
Choosing not to version means accepting that some future change will be harder than it would have been. You will meet a case where a version would have been the clean answer, and you will be doing expand and contract across two quarters instead.
That trade is usually correct, and it is a trade. Teams who never version and never plan for the day they must are the ones who eventually break their consumers without warning, because the option they refused to build was the one they needed.
In Routebase
A specification does not have to declare a versioning strategy at all. With none configured, the panel states plainly that consumers always receive the latest version and that the API operates without version-specific routing, which is the right setting for the situations above.

What replaces the version is verification. Contract tests validate live responses against the published contract, so a change that was supposed to be additive fails the run when it was not. Drift monitors keep doing the same thing against a deployed environment after the release, with the differences reported at field level. Choosing not to version is then a decision you can defend with evidence instead of a hope. The Contract Testing guide covers the validation side, and Contract Drift covers what continues after the release.
Frequently asked questions
Do you always need to version an API?
No. Versioning pays for itself when you cannot reach the people calling you and a change would break them. If every consumer is a team you can talk to, if the API has not promised stability yet, or if the change is additive, a version number adds a support burden and prevents nothing.
What does running multiple API versions cost?
Each live version needs its own tests, its own documentation, its own mock for client teams and its own monitoring, and support answers questions about all of them. New features either get built in every live version or get held back until the old ones retire. The cost is not the branch, it is the years of parallel maintenance after it.
What are the alternatives to API versioning?
Additive change with tolerant readers covers most cases, since a consumer that ignores what it does not read is unaffected by growth. Feature flags let a specific consumer opt into new behaviour without a new contract. The expand and contract pattern ships both shapes for a period and removes the old one once usage reaches zero. Consumer-driven contracts tell you exactly who would break, which often turns a version into a phone call.
Should internal APIs be versioned?
Internal APIs need the classification discipline more than the version numbers. Knowing that a change is breaking is what triggers coordination with the teams that call you. Formal versioning becomes worth it once those teams can no longer deploy in step with you, which is a question about your release process rather than about your API.
Last reviewed by The Routebase Team.