ASP.NET Core  

What Is the Best Way to Handle API Versioning in .NET Core?

Introduction

API versioning in .NET Core is essential for maintaining backward compatibility, enabling smooth feature evolution, and preventing breaking changes for existing clients. As APIs grow and new features are introduced, older consumers must continue functioning without disruption. Implementing a structured API versioning strategy in ASP.NET Core Web API ensures long-term maintainability, controlled releases, and enterprise-grade scalability.

Why API Versioning Is Important

In production environments, APIs are consumed by:

  • Web applications

  • Mobile applications

  • Third-party integrations

  • Microservices

If a response model changes, a route is modified, or a field is removed without versioning, existing consumers may fail. API versioning allows developers to introduce enhancements while preserving legacy behavior.

Common API Versioning Strategies

ASP.NET Core supports multiple API versioning approaches. Each has different trade-offs in terms of clarity, flexibility, and maintainability.

1. URL Path Versioning

Example:

/api/v1/products
/api/v2/products

This is the most commonly recommended and production-friendly approach.

Advantages:

  • Clear and explicit

  • Easy to test and debug

  • Works well with API gateways and reverse proxies

  • Simple routing configuration

This approach is widely adopted in RESTful API design because versioning becomes part of the route structure.

2. Query String Versioning

Example:

/api/products?api-version=1.0

Advantages:

  • Keeps URL structure consistent

  • Easy to implement

However, it is less explicit and sometimes harder to manage in large systems.

3. Header Versioning

Example:

api-version: 1.0

Advantages:

  • Clean URLs

  • Keeps versioning separate from routing

Drawbacks:

  • Harder to test manually

  • Less visible in browser-based testing

  • May require additional documentation for consumers

4. Media Type (Accept Header) Versioning

Example:

Accept: application/json;version=1.0

This approach is more REST-purist but adds complexity and is less commonly used in practical enterprise applications.

Recommended Approach: URL Path Versioning with Microsoft API Versioning Package

The best way to handle API versioning in .NET Core is to use the official API versioning package and implement URL path versioning. It offers clarity, maintainability, and strong tooling support.

Install the NuGet package:

dotnet add package Microsoft.AspNetCore.Mvc.Versioning

Step 1: Configure API Versioning

Inside Program.cs:

builder.Services.AddApiVersioning(options =>
{
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.DefaultApiVersion = new ApiVersion(1, 0);
    options.ReportApiVersions = true;
});

This configuration:

  • Sets default API version

  • Returns supported versions in response headers

  • Improves API discoverability

Step 2: Define Versioned Controllers

Example controller using URL versioning:

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("Products from V1");
    }
}

Create a second version:

[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("Products from V2 with enhanced response");
    }
}

This ensures clean separation between versions while preserving older contracts.

Supporting Multiple Versions in One Controller

You can also map multiple versions within a single controller:

[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    [MapToApiVersion("1.0")]
    public IActionResult GetV1()
    {
        return Ok("Version 1");
    }

    [HttpGet]
    [MapToApiVersion("2.0")]
    public IActionResult GetV2()
    {
        return Ok("Version 2");
    }
}

This approach reduces duplication when differences between versions are minimal.

Versioning Best Practices in Enterprise Applications

  • Never modify an existing version after release

  • Deprecate versions gradually instead of immediate removal

  • Communicate version lifecycle clearly

  • Maintain documentation per version

  • Use semantic versioning (major.minor)

  • Log API usage per version for monitoring

Proper governance prevents version sprawl and technical debt accumulation.

Handling Breaking Changes Safely

When introducing breaking changes:

  • Create a new major version

  • Maintain old version for a transition period

  • Announce deprecation timeline

  • Monitor client migration progress

In microservices architecture, API gateways can route traffic based on version, simplifying traffic management during upgrades.

API Versioning and Swagger Integration

For better developer experience, integrate versioning with Swagger (OpenAPI). Configure Swagger to generate separate documentation per API version. This improves API discoverability and reduces consumer confusion.

When Not to Version

If changes are:

  • Backward compatible

  • Additive (new optional fields)

  • Non-breaking enhancements

You may not need a new version. Over-versioning can increase maintenance overhead.

Summary

The best way to handle API versioning in .NET Core is to implement structured version control using the official API versioning package combined with URL path versioning for clarity and maintainability. By defining explicit versioned routes, preserving backward compatibility, managing breaking changes carefully, and integrating version awareness into documentation and monitoring workflows, teams can build scalable and enterprise-ready ASP.NET Core Web APIs that evolve safely without disrupting existing consumers.