Version your API from day one (URL prefix, header, or query param). Without versioning, any breaking change forces all clients to update simultaneously or breaks them without warning.
Why This Matters
Without API versioning, every change is either backward-compatible or a breaking change that affects all consumers simultaneously. Adding a required field breaks old clients. Removing a field breaks clients that depend on it. Renaming a field breaks everyone. Versioning lets you evolve the API while giving consumers time to migrate, preventing the "deploy and pray" pattern that causes widespread outages.
APIs are contracts. Once a client integrates with your API, they depend on the exact shape of requests and responses. Without versioning, you face a painful choice with every change:
Make it backward-compatible: accumulate debt by never removing deprecated fields, never renaming anything, never changing response shapes. The API becomes a museum of every past decision.
Make a breaking change: break every client simultaneously. Mobile apps in the App Store can't update instantly. Third-party integrations break without warning. Partners lose trust.
Versioning solves this by letting you run old and new versions in parallel. Clients migrate on their own schedule. You deprecate old versions with advance notice. Breaking changes are contained to new versions.
The rule
Version your API from the first release. The three common strategies:
URL prefix is the simplest, most visible, and easiest to route. Use it unless you have a specific reason not to.
Bad example
// BAD: no versioning — /api/users// Changing the response shape breaks all clientsexport async function GET() { const users = await db.user.findMany(); return Response.json( // If you need to change this shape, every client breaks users.map((u) => ({ id: u.id, name: u.name, email: u.email, })) );}
Good example
app/ api/ v1/ users/ route.ts # Original shape v2/ users/ route.ts # New shape — old clients unaffected