Jump to Section
Prerequisites#
Before diving into API versioning, make sure you have a basic setup ready.
You'll need .NET 8 SDK installed, which you can get from the official .NET download page.
A working knowledge of ASP.NET Core and REST API design will also be helpful, though not strictly required.
If you haven’t already created a Web API project, you can quickly generate one using the following commands:
You’ll also need a tool for making API requests, such as Postman or cURL, since we’ll be testing different versioning approaches.
To confirm that your development environment is set up properly, run:
If everything is in place, we’re ready to move on.
Why API Versioning Matters#
APIs evolve. Over time, you may need to introduce new endpoints, modify response formats, or deprecate older features. These changes can cause serious issues for existing clients without a proper versioning strategy.
Imagine an API that powers thousands of applications - introducing breaking changes without warning would create chaos. API versioning allows you to support multiple versions simultaneously, ensuring that older clients continue functioning while newer ones can take advantage of improvements.
Versioning also provides a structured way to deprecate older versions, allowing developers to plan migrations. Instead of forcing all consumers to upgrade immediately, you can provide a transition period where multiple versions coexist. This not only prevents disruptions but also improves maintainability and scalability.
API Versioning Strategies#
There are several approaches to API versioning, each with its own trade-offs.
The choice depends on factors such as API complexity, client needs, and ease of implementation.
Let’s explore the most common strategies and how to implement them in ASP.NET Core.
Strategy 1: Versioning in the URL Path#
One of the simplest and most widely used methods is to include the version number directly in the URL path.
For example:
This approach immediately clears which version is being accessed. It’s easy to implement and doesn’t require clients to send extra headers or query parameters. From a maintenance perspective, each version can have separate controllers, making it easier to manage changes over time.
However, there are some downsides. Embedding the version in the URL modifies the API structure, meaning every new version requires updates to routing. Additionally, this approach isn’t fully RESTful, as the version is a metadata detail rather than a true resource identifier.
Implementation in ASP.NET Core

A request to /api/v1/products returning "This is version 1"

A request to /api/v2/products returning "This is version 2"
Strategy 2: Versioning with Query Parameters#
Another common method is to specify the version as a query parameter, such as:
This method keeps the URL structure unchanged, which can be beneficial if you want to maintain a cleaner API design. It’s easy to implement and doesn’t require modifying routing logic.
However, it relies on clients explicitly providing the version in their requests. If they forget to do so, they may receive an unintended API version, which could lead to unexpected behavior.
Implementation in ASP.NET Core

A Postman request using /api/products?api-version=2.0.
Strategy 3: Versioning with HTTP Headers#
Instead of including the version in the URL or query parameters, you can specify it in the HTTP request headers, like this:
This approach keeps URLs clean and consistent, which aligns better with REST principles. It’s particularly useful when versioning needs to remain transparent to end-users.
However, it also introduces complexity - since most clients don’t send version headers by default, they need to be explicitly configured to do so. Testing in a browser also becomes more difficult, as you can’t easily specify headers without a tool like Postman.
Implementation in ASP.NET Core

A Postman request with the X-Api-Version header set
Strategy 4: Versioning via Subdomains#
A more advanced approach is to use subdomains to differentiate API versions.
In this method, the API version is determined by the domain itself:
This technique provides strong isolation between versions and works well when hosting different API versions on separate infrastructures. Large-scale APIs that require multi-tenancy or dedicated environments for legacy support often use this approach.
However, it requires additional DNS and server configuration, making it more complex to implement and maintain.
Implementation in ASP.NET Core
To implement subdomain-based versioning, we can use middleware that extracts the subdomain and sets the API version accordingly.
Here is pseudo-code:
Configuring API Versioning in ASP.NET Core#
Once you’ve chosen a versioning strategy, you need to configure API versioning in your project.
First, install the required packages:

NuGet packages
Then, modify Program.cs to enable API versioning and integrate it with Swagger:
When you run the project, go to the swagger view, where you can directly test your API calls:

Swagger UI showing multiple API versions
Common Pitfalls and How to Avoid Them#
1. AddVersionedApiExplorer() Not Found
Solution: Use AddApiVersioning() first, then AddApiExplorer():
2. API Versions Not Displayed in Swagger
Solution: Ensure IApiVersionDescriptionProvider is registered:
3. Controllers Do Not Recognize API Versions
Solution: Ensure controllers are decorated with [ApiVersion]:
Final Thoughts: Choosing the Right API Versioning Type#
API versioning is essential for maintaining backward compatibility while allowing for future enhancements.
The right approach depends on your specific use case, API consumers, and long-term maintenance considerations.
Versioning Strategy | Description | Advantages | Disadvantages | Best for |
URL Path Versioning | The version is included in the URL as /api/v1/resource | - Easy to understand and implement - Clients explicitly request a version |
- Modifies API structure over time - Not fully RESTful (version is not a resource) |
Public APIs, clear and explicit versioning needs |
Query String Versioning | The version is passed as ?api-version=1.0 in the URL | - No changes to the API structure - Simple to implement and test |
- Not always intuitive - Less RESTful (query params should filter data, not define API behavior) |
Internal APIs, simple versioning where URL changes are undesirable |
Header Versioning | The version is specified in an HTTP header X-Api-Version: 1.0 | - Keeps URLs clean - More aligned with REST principles |
- Harder to test manually (browsers don’t send headers by default) - Requires explicit client configuration |
APIs requiring strict separation of concerns and a clean URL structure |
Subdomain Versioning | API version is determined by the subdomain (v1.api.example.com) | - Supports hosting different versions separately - Ideal for multi-tenancy and microservices |
- Requires DNS configuration - More complex infrastructure setup |
Large-scale APIs, microservices, multi-tenancy environments |
- Use URL versioning for clarity.
- Use query string versioning for minimal URL changes.
- Use header versioning for a clean URL structure.
- Use subdomain versioning for scalable architectures.
Path and query string versioning are easier to implement, while header and subdomain versioning offer cleaner solutions but require more effort.