.NET Core  

API Versioning in ASP.NET Core: Strategies for Building Backward-Compatible APIs

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.

StrategyExample
URL Path/api/v1/products
Query String/api/products?api-version=1.0
Request HeaderApi-Version: 1.0
Media TypeAccept: 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

ScenarioRecommended Strategy
Public REST APIsURL Path Versioning
Internal APIsHeader Versioning
Enterprise integrationsHeader or Media Type
Mobile applicationsURL Path Versioning
Third-party developersURL 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

ProblemRoot Cause
Breaking existing clientsModifying an existing API version
Version confusionMultiple strategies used simultaneously
Undocumented changesMissing version-specific documentation
Long-term maintenance burdenSupporting obsolete versions indefinitely
Client upgrade issuesNo deprecation policy
Routing conflictsIncorrect 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.