APIs evolve over time. New business requirements, improved data models, enhanced security, and additional features often require changes to existing endpoints. While these changes improve the API, they can also break applications that depend on older versions.
A production API should support evolution without forcing every client to upgrade immediately. This is where API versioning becomes essential. By introducing versioning, developers can add new functionality, deprecate old behavior, and migrate clients gradually without disrupting existing integrations.
In this article, you'll learn how to implement API versioning in ASP.NET Core 10, compare different versioning strategies, and design APIs that remain backward compatible as they evolve.
Why API Versioning Matters
The Problem with Breaking Changes
Imagine an e-commerce API with the following response:
{
"id": 101,
"name": "Laptop",
"price": 1200
}
Months later, the development team changes the response to:
{
"productId": 101,
"productName": "Laptop",
"price": 1200,
"currency": "USD"
}
Although the new response is more descriptive, existing mobile apps, web applications, and third-party integrations expecting id and name will fail.
API versioning allows both versions to coexist while consumers migrate at their own pace.
Common API Versioning Strategies
URL Versioning
The version is included in the URL.
/api/v1/products
/api/v2/products
Advantages
Easy to understand
Visible in logs
Simple routing
Widely adopted
Considerations
Every new version introduces additional endpoints that must be maintained until older versions are retired.
Query String Versioning
The version is passed as a query parameter.
/api/products?api-version=1.0
Advantages
Existing URLs remain unchanged
Easy for testing
Considerations
Version information is less visible, making documentation and debugging slightly more difficult.
Header Versioning
Clients specify the version using an HTTP header.
api-version: 2.0
Advantages
Clean URLs
Flexible client implementations
Considerations
Headers are less discoverable and require additional configuration in API clients and testing tools.
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;
});
Why This Configuration?
This configuration establishes version 1.0 as the default version while allowing existing clients to continue working even if they don't explicitly specify a version.
Enabling ReportApiVersions adds supported API versions to response headers, helping consumers discover available versions.
Versioning Controllers
A controller can explicitly declare the API version it supports.
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/products")]
[ApiController]
public class ProductsController : ControllerBase
{
}
Why Version Controllers?
Explicit version attributes make supported versions clear while allowing multiple controller implementations to coexist.
Each controller focuses on one API contract, reducing complexity and making future maintenance easier.
Supporting Multiple Versions
An API can expose different implementations simultaneously.
Version 1:
GET /api/v1/products
Version 2:
GET /api/v2/products
Both versions can operate independently, allowing organizations to migrate consumers gradually instead of forcing immediate upgrades.
End-to-End Implementation
Consider an online retail platform.
Architecture:
Web App
│
Mobile App
│
Partner API
│
▼
API Gateway
│
┌───┴──────────────┐
▼ ▼
Version 1 Version 2
│ │
Business Services
│
SQL Database
Migration workflow:
Version 1 remains available for existing clients.
Version 2 introduces additional product information.
New applications adopt Version 2.
Existing consumers continue using Version 1 without interruption.
Usage metrics identify when Version 1 can be safely retired.
After communicating the deprecation timeline, Version 1 is removed.
This approach enables continuous API evolution while minimizing disruption for consumers.
Deprecating Older Versions
Eventually, outdated API versions should be retired.
A recommended migration process includes:
Announce deprecation early.
Publish migration documentation.
Encourage adoption of the newer version.
Monitor client usage.
Remove deprecated versions after the announced support period.
Deprecation should be planned carefully to avoid unexpected outages for downstream consumers.
Versioning Strategy Comparison
| Strategy | Advantages | Considerations |
|---|---|---|
| URL Versioning | Simple, visible, widely adopted | Additional routes |
| Query String | Easy testing | Less discoverable |
| Header Versioning | Clean URLs | More client configuration |
| Media Type Versioning | Flexible | Higher implementation complexity |
URL versioning remains the most common choice because it is easy to understand, document, and troubleshoot.
Best Practices
Introduce versioning before the first breaking change.
Keep existing versions stable.
Avoid unnecessary version increments.
Document version differences clearly.
Support multiple versions during migration.
Monitor usage of older versions.
Establish a published deprecation policy.
Use semantic versioning where appropriate.
Test every supported version independently.
Common Mistakes
One common mistake is modifying an existing API contract instead of introducing a new version. Even small property name changes can break client applications.
Another issue is maintaining too many API versions indefinitely. Supporting outdated versions increases maintenance effort and testing complexity.
Developers also sometimes duplicate business logic across versions. Whenever possible, keep shared logic in application services while exposing different API contracts through version-specific controllers.
Testing and Validation
Each API version should be validated independently.
Recommended testing includes:
Endpoint compatibility
Response schema validation
Authentication and authorization
Integration testing
Contract testing
Performance testing
Regression testing
Backward compatibility verification
Automated tests help ensure that introducing a new version does not unintentionally affect existing clients.
Performance Considerations
API versioning itself introduces minimal overhead, but supporting multiple versions can increase application complexity.
Consider these recommendations:
Share business logic between versions.
Cache frequently requested responses.
Optimize database queries.
Remove deprecated versions when appropriate.
Monitor version-specific traffic.
Keep routing configurations straightforward.
Well-designed versioning strategies allow applications to evolve without significant performance impact.
Security Considerations
Security requirements apply consistently across all API versions.
Follow these practices:
Enforce authentication and authorization for every version.
Apply security updates to supported versions.
Validate all inputs.
Use HTTPS for every endpoint.
Audit API access.
Monitor deprecated versions for unusual activity.
Avoid exposing sensitive implementation details through version-specific responses.
Older versions should continue receiving critical security updates until they are officially retired.
Troubleshooting
Clients Receive 404 Errors
Verify that the requested API version matches a registered route and that routing is configured correctly.
Incorrect Version Is Selected
Review the versioning configuration and confirm whether the application expects the version through the URL, query string, or HTTP headers.
Duplicate Controllers Cause Routing Conflicts
Ensure each controller explicitly declares the API version it supports and uses the correct versioned route template.
Clients Continue Using Deprecated Versions
Monitor API usage analytics, communicate deprecation timelines clearly, and provide migration guidance before removing support.
Conclusion
API versioning is essential for building long-lived ASP.NET Core applications that can evolve without breaking existing consumers. By choosing an appropriate versioning strategy, maintaining backward compatibility, and planning migrations carefully, development teams can introduce new capabilities while preserving a stable experience for existing clients. Whether your APIs serve web applications, mobile apps, or third-party integrations, a well-designed versioning strategy ensures continuous evolution with minimal disruption.

Jasen FiciPosted Aug 3, 2026, 1:52 PM
Thanks for sharing this article. We featured it in DotNetNews here: https://dotnetnews.co/archive/the-net-news-daily-issue-510/