How I think about versioning public APIs so clients keep trusting you as the platform evolves.
I've been on both sides of a painful API upgrade. I've been the developer frantically patching an integration because a vendor pushed a "small breaking change" on a Tuesday morning. And I've been the platform owner staring at a list of forty clients, wondering how to move any of them forward without breaking the other thirty-nine.
API versioning is one of those topics that sounds boring until it bites you. Then it's suddenly the most important conversation in the room.
It's really about trust
Here's the thing nobody says out loud: versioning isn't really a technical problem. It's a trust problem.
When someone integrates with your API, they're making a bet that you'll keep your word. Every breaking change is a small withdrawal from that trust. Every clean upgrade path is a deposit. Over time, the balance of those deposits and withdrawals shows up as your reputation — and, eventually, as whether or not serious teams want to build on top of you.
Pick one model and stick to it
There are three common approaches, and I've seen all of them work:
- URL versioning — /v1/users, /v2/users. Loud and obvious. Great for public APIs where discoverability matters.
- Header versioning — clients send an Accept-Version header. Cleaner URLs, but hidden from casual inspection.
- Content negotiation — version is part of the media type. Powerful, but expensive to tool around.
The right answer depends on your audience. The wrong answer is to use all three in different corners of the same platform. I've walked into codebases where the auth endpoints used headers, the billing endpoints used URLs, and a couple of legacy routes did "whatever the original engineer felt like that week." That's not a versioning strategy. That's an archaeological dig.
Treat deprecation like a product feature
The part most teams skip is deprecation. A version you never sunset becomes a version you maintain forever.
A healthy deprecation policy needs a few things: a published timeline so clients can plan, telemetry on who's still calling the old version, concrete migration guides (not just "please upgrade"), and a real end-of-life date that you actually honor.
When you do this well, deprecation stops feeling like punishment and starts feeling like routine maintenance. That's the goal.
Closing thought
Good versioning isn't the flashy part of building an API. But it's one of the clearest signals to your users that you take their time seriously. And in the long run, that matters more than any single feature.