The short answer
If you are a solo founder or a two-person team shipping an API to paying customers, put the version in the URL path (/v1/users, /v2/users). It is the simplest, the easiest to debug in logs, the easiest to cache, and the easiest for a future hire or contractor to understand at a glance. Use header-based or query-parameter versioning only when you have a concrete reason to, because the reasons rarely appear before you have paying traffic.
The harder question is not “how do I version” but “how do I stop supporting the old version without losing customers.” That is where small teams actually burn out, and it is the part most guides skip.
This guide is written for founders building developer-facing products, MCP servers, and AI services where the API is the product. It stays inside three concerns: which versioning scheme to pick, what real deprecation looks like, and how to keep maintenance cost from doubling every time you ship a breaking change.
Why versioning is a founder problem, not just a plumbing problem
When you are the only engineer, versioning feels like overhead. You control the frontend and the backend, so you can just change both at once, right? That works until one of three things happens:
- A paying customer writes an integration against your API and does not want to redeploy when you push a breaking change on a Tuesday afternoon.
- You start reselling access to your service and your customers’ customers need a stable contract.
- You ship an MCP server or AI agent skill that other agents call, and those callers may pin to whatever version you shipped the day they onboarded.
The dossier sources converge on one idea: APIs are effectively forever once something is calling them. Speakeasy puts it bluntly, noting that changing an API after it has been integrated with by various consumers can be very difficult, and breaking changes can disrupt clients and lead to churn. The reason is simple. Even if the change is technically small, the consumer has to schedule time to adapt.
So versioning is really a contract question. Your version number is a promise about which contract is live.
The three real options, stripped down
Most guides list four or five versioning styles. In practice, for a small team you are choosing between three.
1. URI path versioning (/v1/users)
The version is part of the URL. Pros, drawn from the Redocly and Gravitee guides: maximum visibility, trivial to route at the gateway, friendly to HTTP caching, easy to test in Postman or curl, and easy to grep in logs. Cons: the URL is no longer a pure resource identifier, and if you are sloppy you can accumulate parallel route trees that drift apart.
2. Header versioning (Accept: application/vnd.yourapi.v2+json)
The version rides in a header. Redocly and the GitHub discussion thread note it keeps URLs clean and aligns with REST principles, but it hurts discoverability, makes curl debugging slightly annoying, and complicates caching because the version is not part of the cache key by default.
3. Query parameter versioning (/users?version=2)
The version rides in the query string. It is flexible and easy to add without changing routes, but it is the worst of both worlds for caching and for log clarity, and most API gateway tooling treats it as second-class.
The dossier is consistent on this point. Path versioning offers maximum visibility and caching compatibility but requires more URL management. Header versioning aligns with REST principles but reduces discoverability. Query parameter versioning provides flexibility at the cost of caching complexity.
A decision rule for a one-person team
Use this checklist when you are about to write your first route.
- You are shipping a public API and you do not know who will call it. Choose URI path versioning. The visibility benefit compounds over years.
- Your API is a thin MCP or skill surface, and you control every caller. You can get away with no explicit version at all. Add endpoints rather than versions when something breaks, which is the “evolution” strategy Redocly describes. New endpoint, old endpoint kept alive, no global version bump.
- You are building an internal API used only by your own frontend. Skip formal versioning entirely. Coordinate deploys and only formalize a version scheme the day a second consumer appears.
- You already have a gateway or framework that pushes you toward header versioning (some GraphQL and some enterprise gateways). Stay with what the tool gives you. Switching to please a style argument is wasted founder time.
The mistake is choosing header versioning because it is “more RESTful.” REST is an architectural style, not a purity test. For a solo founder, operational ergonomics beat theoretical cleanliness every time.
What deprecation actually requires
This is the section most guides skip, and it is the section that decides whether you keep your customers.
A deprecation is not a blog post. It is a multi-step operation:
- Pick a sunset date and write it into the response. When a client calls a deprecated endpoint, return a
Deprecationheader (orSunsetheader, where your stack supports it) with an ISO date. Some API platforms and gateway vendors support this; check your gateway’s docs because behavior varies. The header is the part machines can act on, which is the part that scales past your first ten customers. - Tell humans in three places. Email your known integrators. Add a banner to your docs. Pin an announcement in any community channel where your API users actually talk.
- Log who is still hitting the old version. You need endpoint-level analytics before you can deprecate with confidence. Redocly calls this out directly: without detailed metrics on endpoint usage, teams make versioning decisions blindly. If you do not have logs that show per-route call counts, stop and fix that first, because you are about to make a decision blind.
- Run a quiet period. At least one full release cycle where the old version still works but the new version is recommended. Two cycles is safer for B2B customers with change boards.
- Move to “warning only.” When the sunset date is near, return a
410 Gonefor the oldest version only if you are confident, or a200with a louder header. Hard kills on a Friday are how you lose accounts. - Sunset. Return
410 Gonewith a pointer to the migration guide.
The whole sequence usually takes three to six months for B2B and one to two release cycles for self-serve developer tools. Budget for it on your roadmap the day you ship v2.
Keeping multiple versions alive without doubling your workload
The honest truth, which the Redocly source states plainly: every additional version increases the surface area for potential issues, and teams often underestimate the long-term cost of maintaining multiple versions when making initial versioning decisions.
Three habits keep that cost in check for a small team.
Share the business logic, branch only at the edge. Write your handlers so that v1 and v2 share services and data access. The version selection happens in a thin router that picks a serializer or response shape, not in duplicated controllers. If you find yourself copy-pasting handlers between versions, you have already lost the cost game.
Version the contract, not the code. Use an OpenAPI or JSON Schema definition per version and generate serializers from it. This is where Redocly and Postman both lean. Generating the shape from a spec means drift between docs and runtime becomes a build error instead of a customer support ticket.
Cap the number of live versions to two. v-current and v-previous. When v-next ships, v-oldest goes into “warning only” mode. If a customer refuses to migrate after the warning period, that is a sales conversation, not an engineering one. Pricing or extended-support contracts are how mature APIs handle this; small teams usually cannot afford to, and that is the lever you pull.
A practical first-time setup
If you are about to ship your first public endpoint this week, here is a minimal setup that will not paint you into a corner.
- Pick URI path versioning. Route
/v1/*to a router, and put your real handlers behind it. - Generate an OpenAPI file for
/v1from your code or your code from the spec, whichever your stack prefers. - Add structured request logging that includes the route template, not just the URL, so you can grep for
v1/versusv2/later. - Add a
DeprecationandSunsetresponse header convention to your gateway, even if you have nothing deprecated yet. Retrofitting it across handlers later is painful. - Write a one-page deprecation policy. Date format, contact channel, minimum notice period. Paste it into your docs before you need it.
None of this is free, but it is all cheaper than the first time you push a breaking change at midnight and your biggest customer’s integration breaks with it.
FAQ
Is semantic versioning (1.2.3) the same as API versioning?
No. Semver is a useful labeling system for the version string you expose, but the mechanism (URI vs header vs query) is a separate decision. Many teams use semver-like labels in the URI anyway, e.g., /v2/ for breaking changes and a 2.4.x label in the changelog.
Do I need to version if I am the only consumer? No. Coordinate deploys. Formalize a version scheme the day a second consumer appears, whether that consumer is another team, an MCP caller, or a paying customer.
What is the difference between versioning and evolution? Evolution means you add new endpoints instead of bumping versions, keeping a single live version. Redocly describes GraphQL as the canonical example. It works well when you control the schema and want to avoid parallel code paths. It works less well when consumers are doing code generation against a fixed contract.
How long should I support an old version? There is no industry-wide rule, and major platforms vary widely. A safe default for a small B2B SaaS is three to six months from announcement to sunset, with one quiet period and one warning period.
Should I ever use header versioning? Yes, when your gateway or framework already does, or when you have a strong reason to keep URLs identical across versions. Otherwise, prefer URI path versioning for the operational reasons above.
Sources
- https://www.gravitee.io/blog/api-versioning-best-practices
- https://daily.dev/blog/api-versioning-strategies-best-practices-guide
- https://www.xmatters.com/blog/api-versioning-strategies
- https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design
- https://redocly.com/blog/api-versioning-best-practices
- https://github.com/orgs/community/discussions/158828
- https://www.postman.com/api-platform/api-versioning
- https://www.speakeasy.com/api-design/versioning







