api-versioning
codewithmukesh/dotnet-claude-kit
API versioning strategies for ASP.NET Core using Asp.Versioning library with URL, header, and query string approaches.
What is api-versioning?
Implement API versioning in ASP.NET Core to manage breaking changes and maintain backward compatibility. Use this skill when adding versioning to a new API, evolving an existing API with breaking changes, or when the user mentions version management, deprecation, or backward compatibility.
- Set up Asp.Versioning library with URL segment, header, or query string strategies
- Organize endpoints into version-specific groups with separate response shapes
- Mark API versions as deprecated and communicate sunset dates to clients
- Integrate versioning with OpenAPI/Swagger documentation
- Map version-specific endpoint handlers that transform responses per version
How to install api-versioning
npx skills add https://github.com/codewithmukesh/dotnet-claude-kit --skill api-versioning- ASP.NET Core 6.0 or later
- Asp.Versioning NuGet package installed
- Basic understanding of ASP.NET Core routing and minimal APIs
How to use api-versioning
- 1.Install Asp.Versioning via NuGet and configure it in Program.cs with an ApiVersionReader strategy
- 2.Choose a versioning strategy: URL segment (recommended for public APIs), header (for internal APIs), or query string
- 3.Create separate endpoint handler classes for each version (e.g., OrderEndpointsV1, OrderEndpointsV2)
- 4.Map endpoint groups using MapGroup with version sets and route to version-specific handlers
- 5.Mark versions as deprecated using HasDeprecatedApiVersion() when releasing a new version
- 6.Test that clients receive correct response shapes and deprecation headers
Use cases
- Adding versioning to a new public API from day one to avoid painful refactoring later
- Releasing a breaking change by creating a new version while keeping the old version available
- Deprecating an old API version with a timeline and migration guidance for clients
- Supporting multiple response shapes for the same endpoint across different versions
- Organizing internal service-to-service APIs using header-based versioning for cleaner URLs
- ASP.NET Core API developers managing public or internal APIs
- Backend engineers evolving APIs with breaking changes
- Teams needing to maintain multiple API versions simultaneously
- Architects designing API deprecation strategies
api-versioning FAQ
Version the entire API group. All endpoints in a version should share the same version number for consistency. Versioning individual endpoints creates confusion and maintenance overhead.
URL segment versioning (/api/v1/orders) is recommended because it's discoverable, cache-friendly, and follows REST conventions. Header versioning is better for internal service-to-service APIs.
Create a new version with the breaking change and keep the old version running. Mark the old version as deprecated with a sunset date, then provide clear migration documentation for clients.
Yes. Adding optional fields is backward compatible and does not require a new version. Only breaking changes—removing fields, changing types, or altering behavior—require a new version.
Use the api-deprecated-versions response header (set automatically by Asp.Versioning) and document the sunset date and migration path in your API documentation.
Full instructions (SKILL.md)
Source of truth, from codewithmukesh/dotnet-claude-kit.
name: api-versioning description: > API versioning strategies for ASP.NET Core. Covers Asp.Versioning library, URL segment, header, and query string strategies, version deprecation, and OpenAPI integration. Load this skill when adding versioning to an API, evolving an API with breaking changes, or when the user mentions "API version", "versioning", "v1/v2", "Asp.Versioning", "deprecation", "breaking change", or "backward compatibility".
API Versioning
Core Principles
- Version from day one — Adding versioning later is painful. Start with a version in the URL even if you only have v1.
- URL segment versioning is the default —
/api/v1/ordersis the most discoverable and cache-friendly strategy. - Never break existing versions — Add a new version for breaking changes. Deprecate the old version with a timeline.
- Version the API, not individual endpoints — All endpoints in a version group share the same version number.
Patterns
Setup with Asp.Versioning
// Program.cs
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = new UrlSegmentApiVersionReader();
})
.AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
URL Segment Versioning (Recommended)
var v1 = app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(1, 0))
.Build();
var v2 = app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(2, 0))
.Build();
app.MapGroup("/api/v{version:apiVersion}/orders")
.WithApiVersionSet(v1)
.WithTags("Orders")
.MapOrderEndpointsV1();
app.MapGroup("/api/v{version:apiVersion}/orders")
.WithApiVersionSet(v2)
.WithTags("Orders")
.MapOrderEndpointsV2();
Header Versioning (Alternative)
options.ApiVersionReader = new HeaderApiVersionReader("X-Api-Version");
// Client sends: X-Api-Version: 2.0
Deprecating a Version
var v1 = app.NewApiVersionSet()
.HasDeprecatedApiVersion(new ApiVersion(1, 0))
.HasApiVersion(new ApiVersion(2, 0))
.Build();
// Response headers will include: api-deprecated-versions: 1.0
Version-Specific Endpoint Groups
public static class OrderEndpointsV1
{
public static RouteGroupBuilder MapOrderEndpointsV1(this RouteGroupBuilder group)
{
group.MapGet("/{id:guid}", GetOrderV1);
group.MapPost("/", CreateOrderV1);
return group;
}
private static async Task<Results<Ok<OrderResponseV1>, NotFound>> GetOrderV1(
Guid id, ISender sender, CancellationToken ct)
{
// V1 response shape
var result = await sender.Send(new GetOrder.Query(id), ct);
return result.IsSuccess
? TypedResults.Ok(result.Value.ToV1())
: TypedResults.NotFound();
}
}
public static class OrderEndpointsV2
{
public static RouteGroupBuilder MapOrderEndpointsV2(this RouteGroupBuilder group)
{
group.MapGet("/{id:guid}", GetOrderV2);
group.MapPost("/", CreateOrderV2);
return group;
}
private static async Task<Results<Ok<OrderResponseV2>, NotFound>> GetOrderV2(
Guid id, ISender sender, CancellationToken ct)
{
// V2 response shape — includes new fields
var result = await sender.Send(new GetOrder.Query(id), ct);
return result.IsSuccess
? TypedResults.Ok(result.Value.ToV2())
: TypedResults.NotFound();
}
}
Anti-patterns
Don't Version Individual Endpoints
// BAD — inconsistent versioning within a group
app.MapGet("/api/v1/orders", ListOrdersV1);
app.MapGet("/api/v2/orders/{id}", GetOrderV2); // V2 only for this endpoint?
// GOOD — version the entire group
app.MapGroup("/api/v1/orders").MapOrderEndpointsV1();
app.MapGroup("/api/v2/orders").MapOrderEndpointsV2();
Don't Use Query String Versioning as Default
// BAD for REST APIs — version hidden in query string, not cache-friendly
GET /api/orders?api-version=2.0
// GOOD — version in URL, discoverable and cacheable
GET /api/v2/orders
Decision Guide
| Scenario | Recommendation |
|---|---|
| New public API | URL segment versioning from day one |
| Internal API between services | Header versioning (cleaner URLs) |
| Breaking response shape change | New version |
| Adding new optional fields | Same version (backwards compatible) |
| Deprecating a version | Mark deprecated, set sunset date, document migration path |
Related skills
More from codewithmukesh/dotnet-claude-kit and the wider catalog.

arch-check
Verify your codebase matches its declared architecture—catch dependency violations, layer leaks, and cycles.

architecture-advisor
Guided architecture selection for .NET apps—asks structured questions, recommends Vertical Slice, Clean, DDD+Clean, or Modular Monolith.

aspire
Orchestrate cloud-native .NET services locally with AppHost, service discovery, and integrated observability.

authentication
JWT, OpenID Connect, and policy-based authorization for ASP.NET Core APIs and web apps.

build-fix
Autonomous iteration loops that drive broken .NET builds and failing tests to green with bounded retries and fail-safe guards.

caching
HybridCache and output caching strategies for .NET 10 applications with stampede protection.