Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›REST API Design›API Versioning Strategies

REST Principles

API Versioning Strategies

API versioning allows developers to evolve their services by introducing changes while maintaining compatibility for existing clients. It is a critical aspect of API design that prevents breaking changes from disrupting production traffic for downstream consumers. You must implement a clear versioning strategy as soon as you identify the need to change resource schemas, update business logic, or deprecate endpoints without forcing immediate updates on all users.

URI Path Versioning

URI path versioning is the most explicit and common approach to API versioning. By embedding the version identifier directly into the URL path, you communicate the API contract clearly at the resource level. This approach is highly visible to both developers and infrastructure, as network proxies, load balancers, and caching layers can easily route requests based on the prefix. Because the version is part of the resource identifier, it is fundamentally impossible for a client to accidentally hit the wrong version of your API. Furthermore, this method is browser-friendly; a developer can simply type the URL into a web browser to inspect the output. The downside is that the version becomes part of the identifier, which technically means that '/v1/users/1' and '/v2/users/1' represent different entities conceptually. Despite this, it remains the gold standard for many teams because it is robust, easy to debug, and requires no special request headers or complex logic.

GET /api/v1/orders/55 HTTP/1.1
Host: api.example.com
# The version is clearly defined in the URI path,
# making it immediately obvious to the developer
# and easy to route via server configurations.

Query Parameter Versioning

Query parameter versioning shifts the version declaration from the resource path to a parameter appended to the query string. This method is often chosen when the API designers want to keep the URI path strictly focused on the resource hierarchy itself. The logic here relies on the server inspecting the query string to determine which controller or service layer logic to trigger. While this keeps the 'resource' part of the URL 'clean,' it is slightly less intuitive for developers and can complicate caching policies, as different versions might be interpreted as the same resource by naive caching intermediaries unless they are explicitly configured to respect query parameters. From an architecture standpoint, this strategy is useful when you want to avoid structural changes to your routing table, allowing you to route requests to different function implementations based on conditional checks at the start of your request handling pipeline. It offers flexibility but requires disciplined documentation to ensure clients pass the necessary version identifiers consistently.

GET /orders/55?version=2 HTTP/1.1
Host: api.example.com
# The resource path remains static while the 
# version is handled as a variable, allowing
# the server to route requests internally.

Custom Header Versioning

Custom header versioning represents a 'cleaner' look for your URIs by moving versioning metadata entirely out of the URL string. In this paradigm, the client specifies which version of the API they desire via a specific HTTP header, such as 'X-API-Version'. This approach treats your URIs as immutable, resource-focused identifiers that do not need to change even when the underlying data schema evolves. The fundamental philosophy here is that the resource exists independently of its representation or version. By shifting this requirement to a header, you decouple the resource identification from the versioning logic. However, this creates a discovery challenge: clients cannot simply copy-paste a URL into a browser to see a specific version. Additionally, it increases complexity for middle-tier network appliances that might not be configured to consider custom headers when making routing or caching decisions. This method is best suited for internal-facing or highly controlled client environments where the team manages both the server-side code and the client implementation.

GET /orders/55 HTTP/1.1
Host: api.example.com
X-API-Version: 2.0
# The URI remains constant while the version 
# is negotiated through metadata headers.

Media Type Versioning (Content Negotiation)

Media type versioning, often referred to as 'Accept Header' versioning, represents the most advanced and REST-philosophically pure approach. Instead of treating the version as a separate entity, you treat it as a specific 'media type' or representation of the resource. You request the version via the 'Accept' header using a custom vendor media type. This allows a single URL to return a version 1 response or a version 2 response based solely on what the client declares it is capable of parsing. This approach is powerful because it allows for granular evolution; you could technically return different versions of the same resource to the same client based on which 'Accept' header they send. This forces developers to think about content negotiation, which is a core concept of the transfer protocol. While it is the most elegant way to handle multiple schemas for the same resource, it significantly increases the complexity of your server-side rendering or serialization logic, as you must maintain multiple content-type handlers for every single endpoint you expose.

GET /orders/55 HTTP/1.1
Host: api.example.com
Accept: application/vnd.example.v2+json
# The client negotiates the specific representation
# version via the Accept header field.

Deprecation and Sunset Headers

Once you have established a versioning strategy, you must eventually deal with the sunsetting of old versions. Simply deleting an old version causes catastrophic failures for legacy clients. Instead, you should utilize the standard 'Sunset' and 'Deprecation' headers to inform clients that their current integration is nearing its end-of-life. The 'Deprecation' header indicates that the endpoint is no longer recommended for new projects, while the 'Sunset' header specifies the exact date and time the endpoint will be permanently removed. This allows your client teams to schedule their migrations systematically rather than reacting to an unexpected outage. By providing these temporal indicators, you build trust with your users and demonstrate a commitment to API stability. You should always combine these headers with proactive logging to identify which clients are still hitting the legacy versions so that you can provide direct outreach or support for their migration journey. This proactive lifecycle management is as important as the versioning choice itself.

GET /v1/orders/55 HTTP/1.1
Host: api.example.com
Deprecation: true
Sunset: Wed, 31 Dec 2025 23:59:59 GMT
# These headers proactively warn the client 
# about the upcoming retirement of the resource.

Key points

  • URI path versioning is the most explicit and easiest to debug for external developers.
  • Query parameter versioning allows for cleaner URLs but complicates server-side routing logic.
  • Custom header versioning separates resource identification from versioning concerns.
  • Media type versioning leverages the power of content negotiation to provide multiple resource representations.
  • Versioning should be implemented early to protect clients from breaking changes during growth.
  • Using Sunset and Deprecation headers provides a transparent lifecycle for legacy API versions.
  • Decoupling the API version from the resource identifier can lead to a more REST-compliant architecture.
  • Every versioning strategy requires trade-offs between architectural purity and developer ease-of-use.

Common mistakes

  • Mistake: Changing versions via request bodies. Why it's wrong: Versioning should be metadata-driven (URL or headers) to keep the resource representation clean. Fix: Use URI path versioning or custom request headers.
  • Mistake: Versioning every single minor patch. Why it's wrong: It creates unnecessary fragmentation and maintenance overhead for consumers. Fix: Use Semantic Versioning and only increment the major version for breaking changes.
  • Mistake: Neglecting to provide a default version. Why it's wrong: It breaks existing clients when you introduce a new version. Fix: Always ensure requests without a version header fall back to a stable, well-defined default version.
  • Mistake: Mixing multiple versioning strategies in one API. Why it's wrong: It confuses developers and makes documentation/caching extremely difficult. Fix: Choose one strategy (e.g., URI path) and stick to it consistently across the entire API.
  • Mistake: Permanently deleting old versions without notice. Why it's wrong: It causes immediate downtime for dependent integrations. Fix: Implement a formal sunset policy with deprecation headers before removing support.

Interview questions

What is the primary purpose of versioning a REST API, and why is it essential for long-term maintenance?

The primary purpose of versioning is to enable evolution while maintaining backward compatibility. As systems grow, requirements change, necessitating structural shifts in data models or business logic. Without versioning, a breaking change would instantly crash all existing client integrations. Versioning allows developers to introduce new features or change response formats in a 'v2' endpoint while keeping the 'v1' endpoint stable, providing a controlled migration path for consumers, ensuring that legacy clients remain functional while newer clients adopt modern standards.

How does URI path versioning work, and what are its main advantages and disadvantages?

URI path versioning involves embedding the version number directly into the resource path, for example, 'https://api.example.com/v1/users'. The main advantage is visibility and simplicity; it is easily cached by infrastructure, and developers can immediately identify the API version by looking at the URL. However, the disadvantage is that it violates the REST principle that a URI should represent a unique resource. By changing the path to '/v2/', you are technically creating a new URI for the same resource, which can lead to redundancy in implementation.

Explain how versioning via Custom Headers works as an alternative to URL versioning.

Versioning via headers, such as using a 'X-API-Version' header, keeps the URI clean because the resource identifier remains consistent regardless of the version being requested. The client sends 'X-API-Version: 2' in the request, and the server routes the logic accordingly. This approach adheres better to the REST concept of resource identifiers. The downside is that it can make caching more complex, as the cache key must now include the custom header, and it is less visible to developers who are debugging or inspecting requests simply by viewing the URL in a browser.

Compare URI path versioning with Media Type versioning (Content Negotiation). Which is generally preferred in strict RESTful design?

URI path versioning is easier to implement and debug, but Media Type versioning, often called 'Content Negotiation', is arguably more 'RESTful'. In Media Type versioning, the client specifies the version in the 'Accept' header, like 'Accept: application/vnd.myapi.v2+json'. This allows the same URI to return different representations of the same resource. While Media Type versioning is powerful and avoids URI bloat, it is significantly harder to test and implement because it requires complex server-side logic to parse headers and negotiate the correct format, whereas URI versioning is straightforward and universally supported by all infrastructure tools.

When should you decide to release a new major version versus keeping the API backward compatible?

A new major version should be released only when breaking changes are unavoidable. Examples include removing fields from a JSON response, renaming required parameters, changing the authentication flow, or altering the semantics of an HTTP status code. If a change is additive—such as adding a new optional field—it should be implemented in the current version without incrementing the major version. Maintaining backward compatibility is always preferred because it prevents the high cost of forcing all consumers to update their client code immediately, which helps preserve the developer ecosystem and trust.

How would you implement a deprecation strategy for an older version of a REST API to minimize consumer frustration?

An effective deprecation strategy requires communication and technical markers. First, you should introduce the 'Sunset' and 'Deprecation' HTTP headers to inform clients that an endpoint will be removed at a specific future date. Additionally, you should include a warning field in the API response payload. You must provide clear documentation detailing the migration steps from the old version to the new one. Finally, monitor usage logs to identify clients that have not migrated, reaching out to them directly before the hard-shutdown date to ensure they have sufficient time to transition their infrastructure, preventing accidental production downtime.

All REST API Design interview questions →

Check yourself

1. When deciding between URI versioning and Header versioning, which factor best dictates the choice?

  • A.The number of endpoints in the API
  • B.Whether you want to leverage browser caching for resources
  • C.The preference of the backend programming framework
  • D.The size of the request payloads
Show answer

B. Whether you want to leverage browser caching for resources
URI versioning is transparent to web caches, meaning a change in version URL acts as a new cache key. Header versioning is cleaner for RESTful principles but makes caching more complex, requiring the Vary header. The other options are irrelevant to the architectural trade-offs.

2. A team introduces a non-breaking field to a JSON object in an existing version. What is the standard approach regarding versioning?

  • A.Bump the major version number
  • B.Require a new header version indicator
  • C.Maintain the current version, as this is an additive change
  • D.Create a new sub-resource for the added field
Show answer

C. Maintain the current version, as this is an additive change
Non-breaking changes, such as adding a field or optional parameter, should not trigger a version bump, as clients ignoring unknown fields will continue to function. Bumping a version for non-breaking changes forces unnecessary upgrades. The other options are overkill for backwards-compatible additions.

3. Why is it recommended to use a 'Sunset' header when deprecating an API version?

  • A.To inform the client of the specific date the version will cease to function
  • B.To provide a link to the new documentation
  • C.To indicate that the server is currently under maintenance
  • D.To signal that the current version is experimental
Show answer

A. To inform the client of the specific date the version will cease to function
The Sunset HTTP header is the standard way to communicate the expiration date of an API version to clients. Providing a link, maintenance status, or experimental status does not solve the fundamental issue of communicating a firm cutoff date.

4. If you follow REST principles, why might some architects dislike URI path versioning like /v1/resource?

  • A.Because it makes the API harder to authenticate
  • B.Because it treats the version as part of the resource identifier rather than metadata
  • C.Because it prevents the use of SSL/TLS
  • D.Because it is incompatible with mobile applications
Show answer

B. Because it treats the version as part of the resource identifier rather than metadata
REST treats a URI as the identifier for a resource. Adding '/v1/' suggests that the resource itself changes identity, rather than just the representation. The other options are incorrect, as URI versioning is compatible with authentication, SSL, and mobile platforms.

5. Which of the following describes the correct usage of Media Type versioning (Content Negotiation)?

  • A.Versioning based on the file extension like .jsonv1
  • B.Including the version in the Accept header via vendor-specific media types
  • C.Embedding the version in the query parameter
  • D.Using the User-Agent string to detect the version
Show answer

B. Including the version in the Accept header via vendor-specific media types
Media type versioning involves headers like 'Accept: application/vnd.myapi.v1+json'. This keeps the URI clean and adheres to the spirit of REST content negotiation. File extensions, query parameters, and User-Agent sniffing are either non-standard or violate the core design intent of clean resource identification.

Take the full REST API Design quiz →

← PreviousResource Naming and URL DesignNext →Idempotency and Safety

REST API Design

24 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app