ASP.NET Core  

How to Implement API Versioning in ASP.NET Core?

API versioning is a critical practice in modern application development that allows teams to evolve APIs without breaking existing clients. In enterprise ASP.NET Core applications, APIs are often consumed by mobile apps, third-party systems, frontend frameworks, and microservices. If a breaking change is introduced without versioning, it can cause production outages, client failures, and revenue loss. This guide explains API versioning in ASP.NET Core in a production-grade manner, including definitions, internal behavior, real-world scenarios, implementation strategies, comparison approaches, advantages, trade-offs, and best practices.

What is API Versioning?

API versioning is the strategy of maintaining multiple versions of an API simultaneously so that changes can be introduced without affecting existing consumers.

Real-world analogy:

Think of API versioning like smartphone operating system updates. When a new OS version is released, older apps still continue working because backward compatibility is maintained. Similarly, when you release v2 of your API, clients using v1 should not break immediately.

Without versioning:

  • Changing a response model may break mobile applications

  • Removing a property may cause frontend crashes

  • Modifying route structure may fail integrations

With versioning:

  • Existing clients continue using v1

  • New clients adopt v2

  • Gradual migration becomes possible

Why API Versioning is Important in Production

Consider a fintech ASP.NET Core API that returns transaction data:

Version 1 response:

{
  "id": 1,
  "amount": 5000
}

Later, business requires currency support:

Version 2 response:

{
  "id": 1,
  "amount": 5000,
  "currency": "INR"
}

If currency is added without versioning and frontend validation expects exact schema, it may fail. Versioning ensures structured evolution.

Common API Versioning Strategies

  • URL Versioning

  • Query String Versioning

  • Header Versioning

  • Media Type Versioning

Each approach has different use cases and trade-offs.

Difference Between API Versioning Strategies

StrategyExampleVisibilityEase of TestingREST PurityRecommended For
URL Versioning/api/v1/productsVery ClearEasyModeratePublic APIs
Query String/api/products?api-version=1.0VisibleEasyGoodInternal APIs
Header VersioningHeader: api-version: 1.0HiddenMediumHighEnterprise APIs
Media TypeAccept: application/json;v=1.0HiddenComplexVery HighStrict REST systems

In most real-world ASP.NET Core applications, URL versioning is preferred for clarity and simplicity.

Step 1: Install API Versioning Package

dotnet add package Microsoft.AspNetCore.Mvc.Versioning

Step 2: Configure API Versioning in Program.cs

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();

app.Run();

Explanation:

  • DefaultApiVersion sets fallback version.

  • AssumeDefaultVersionWhenUnspecified prevents client failures.

  • ReportApiVersions adds supported versions in response headers.

Step 3: Implement URL Versioning in Controller

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("1.0")]
public class ProductsV1Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new { Message = "Products from Version 1" });
    }
}

[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("2.0")]
public class ProductsV2Controller : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new { Message = "Products from Version 2 with enhancements" });
    }
}

Now:

  • /api/v1/products → returns V1 response

  • /api/v2/products → returns V2 response

Alternative: Query String Versioning

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader = new QueryStringApiVersionReader("api-version");
});

Request example:

/api/products?api-version=2.0

Alternative: Header Versioning

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader = new HeaderApiVersionReader("api-version");
});

Client must send header:

api-version: 2.0

Real Production Scenario

An e-commerce company releases a mobile app integrated with API v1. Later, API v2 introduces discount logic changes. If v1 is removed immediately, older mobile app users experience crashes. By maintaining both versions, users update gradually without service disruption.

This approach prevents breaking changes in distributed systems.

Advantages of API Versioning

  • Prevents breaking client applications

  • Enables controlled API evolution

  • Supports backward compatibility

  • Allows phased migration

  • Improves maintainability in large systems

Disadvantages and Trade-offs

  • Increased maintenance cost

  • Duplicate controller logic

  • Complex documentation management

  • Requires disciplined deprecation strategy

Common Mistakes Developers Make

  • Removing old versions too early

  • Not documenting version differences

  • Overusing versioning for minor changes

  • Mixing multiple versioning strategies

  • Ignoring deprecation communication

Best Practices for Enterprise Applications

  • Use URL versioning for public APIs

  • Maintain clear changelog

  • Deprecate versions gradually

  • Use semantic versioning (1.0, 2.0)

  • Combine versioning with proper API documentation (Swagger)

  • Avoid breaking changes within same version

When to Introduce a New API Version

Create a new version when:

  • Response schema changes

  • Property names change

  • Business logic changes impact output

  • Authentication mechanism changes

Avoid new version when:

  • Adding optional fields

  • Adding new endpoints

  • Improving internal performance without contract change

Summary

Implementing API versioning in ASP.NET Core enables safe and controlled evolution of APIs without breaking existing clients. By configuring API versioning services, selecting an appropriate strategy such as URL, query string, or header versioning, and maintaining multiple controller versions, organizations can introduce new features while preserving backward compatibility. Although versioning increases maintenance complexity, it is essential for enterprise-grade systems where APIs are consumed by multiple external clients. A disciplined versioning and deprecation strategy ensures long-term stability, scalability, and seamless user experience in modern distributed applications.