APIs evolve over time. New features are added, response models change, endpoints are deprecated, and business requirements shift. Without a clear versioning strategy, even small API changes can break existing clients and create costly compatibility issues.
ASP.NET Core supports API versioning through multiple strategies, allowing you to introduce new functionality while maintaining backward compatibility for existing consumers. Choosing the right versioning approach helps reduce breaking changes, simplifies client upgrades, and enables long-term API maintenance.
Rather than treating versioning as an afterthought, this article explains the most common API versioning strategies, how to implement them in ASP.NET Core, and when each approach is appropriate.
Note: API versioning is not only about supporting multiple versions simultaneously. It's also about providing a predictable upgrade path for API consumers.
Why API Versioning Matters
Without versioning, introducing changes can result in:
Broken client applications
Failed mobile app updates
Integration failures
Increased maintenance costs
Difficult deployments
Poor developer experience
A well-defined versioning strategy allows APIs to evolve without disrupting existing integrations.
Common Versioning Strategies
ASP.NET Core supports several versioning approaches.
| Strategy | Example |
|---|
| URL Path | /api/v1/products |
| Query String | /api/products?api-version=1.0 |
| Request Header | Api-Version: 1.0 |
| Media Type | Accept: application/json;version=1.0 |
Each strategy has advantages depending on the API's consumers and deployment model.
URL Versioning
URL versioning is the most common and easiest approach to understand.
Example endpoint:
GET /api/v1/products
GET /api/v2/products
Clients explicitly specify which version they want to consume, making debugging and documentation straightforward.
Installing API Versioning
Install the required NuGet package.
dotnet add package Asp.Versioning.Mvc
This package adds API versioning support to ASP.NET Core applications.
Configuring API Versioning
Register API versioning during application startup.
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion =
new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});
This configuration automatically assumes version 1.0 when a client doesn't specify an API version.
Creating a Versioned Controller
Decorate controllers using the ApiVersion attribute.
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok();
}
}
Requests targeting /api/v1/products are automatically routed to this controller.
Supporting Multiple Versions
A controller can support multiple API versions.
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ProductsController : ControllerBase
{
}
This approach is useful when most functionality remains unchanged across versions.
Creating a New API Version
As APIs evolve, newer versions can expose additional functionality.
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/products")]
public class ProductsV2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok(new
{
Version = "2.0",
SupportsDiscounts = true
});
}
}
Creating separate controllers often improves maintainability when versions diverge significantly.
API Version Lifecycle
flowchart LR
A[Version 1]
B[Version 2]
C[Version 3]
D[Deprecation]
E[Retirement]
A --> B
B --> C
C --> D
D --> E
Versioning allows new functionality to be introduced while giving clients time to migrate.
Deprecating an API Version
Older versions should eventually be deprecated.
[ApiVersion("1.0", Deprecated = true)]
public class ProductsController : ControllerBase
{
}
Clients can be notified that the version will be removed in a future release.
Versioning with Swagger
Swagger can generate separate documentation for each API version.
Benefits include:
Clear API documentation
Independent version discovery
Easier client integration
Simplified testing
Better developer experience
Maintaining separate documentation reduces confusion during API evolution.
Choosing the Right Versioning Strategy
| Scenario | Recommended Strategy |
|---|
| Public REST APIs | URL Path Versioning |
| Internal APIs | Header Versioning |
| Enterprise integrations | Header or Media Type |
| Mobile applications | URL Path Versioning |
| Third-party developers | URL Path Versioning |
URL versioning is generally the easiest approach for public APIs because it is visible, cache-friendly, and well supported by tooling.
Common Production Mistakes
| Problem | Root Cause |
|---|
| Breaking existing clients | Modifying an existing API version |
| Version confusion | Multiple strategies used simultaneously |
| Undocumented changes | Missing version-specific documentation |
| Long-term maintenance burden | Supporting obsolete versions indefinitely |
| Client upgrade issues | No deprecation policy |
| Routing conflicts | Incorrect versioned routes |
Most versioning problems result from planning issues rather than technical limitations.
Best Practices
Introduce a new version for breaking changes.
Maintain backward compatibility whenever possible.
Document every supported API version.
Establish a clear deprecation policy.
Support older versions only as long as necessary.
Version contracts rather than implementation details.
Keep version numbering consistent across the API.
Common Anti-Patterns
Avoid these common mistakes:
Modifying response contracts without creating a new version.
Supporting every historical version indefinitely.
Mixing multiple versioning strategies within the same API.
Removing deprecated versions without advance notice.
Embedding version numbers inside business logic.
Treating versioning as a replacement for proper API design.
FAQ
When should I create a new API version?
Create a new version whenever you introduce a breaking change, such as removing properties, changing response formats, or modifying endpoint behavior in a way that affects existing clients.
Which versioning strategy is most common?
URL path versioning is the most widely adopted approach because it is easy to understand, works well with API gateways, and integrates seamlessly with documentation tools.
Can multiple API versions run simultaneously?
Yes. ASP.NET Core allows multiple versions of the same API to coexist, enabling clients to migrate gradually without disrupting existing integrations.
Should every minor feature require a new API version?
No. Backward-compatible additions, such as optional response fields or new endpoints, typically don't require a new version. Reserve version changes for breaking modifications.
Conclusion
API versioning is essential for building maintainable and consumer-friendly ASP.NET Core applications. By introducing new versions only when necessary, documenting changes clearly, and providing a structured deprecation strategy, you can evolve your APIs without disrupting existing clients.
Whether you choose URL path, query string, header, or media type versioning, the goal remains the same: enable continuous API evolution while preserving backward compatibility and delivering a predictable experience for every API consumer.