vertical-slice · codewithmukesh — Claude Code skill: what it does, how to install
Guides .NET architecture toward feature-based vertical slices instead of layered folders. Helps structure endpoints, request models, and handlers together.
npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a claude-codeWhat vertical-slice does
This skill shifts .NET projects away from layered Controllers, Services, and Repositories folders. Each feature lives in its own slice with its endpoint, command, AbstractValidator rules, and response types. Cross-feature coupling drops because features do not reference each other directly. Shared logic moves into Common/ or Shared/.
It provides three distinct handler implementations. The default recommendation uses source-generated Mediator via Mediator.Abstractions and Mediator.SourceGenerator, which avoids reflection and stays Native AOT compatible. The second approach follows Wolverine conventions using a static Handle method. The third relies on plain classes with an ExecuteAsync method and zero third-party packages.
Larger systems can split features into dedicated class library modules with individual DbContext instances. Relying on raw handlers without a mediator library makes sense only for smaller codebases where manual wiring beats pipeline behaviors.
What it helps with
- organize .NET API code by feature folders
- implement request handlers using source-generated Mediator
- set up convention-based handling with Wolverine
- isolate feature logic into single-file endpoints without mediator libraries
Example prompts for the agent
- Structure the CreateOrder feature using Vertical Slice Architecture and FluentValidation.
- Implement a Native AOT compatible handler using source-generated Mediator for my .NET API.
- Show me how to write a raw handler endpoint in .NET without external mediator libraries.
How to install vertical-slice
1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a claude-code2Manually: put the files in place
~/.claude/skills/vertical-slice/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/vertical-slice/
1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a codex2Manually: put the files in place
.agents/skills/vertical-slice/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a cursor2Manually: put the files in place
.cursor/skills/vertical-slice/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install codewithmukesh/dotnet-claude-kit vertical-slice2Manually: put the files in place
.github/skills/vertical-slice/SKILL.md1Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a gemini-cli2Platform CLI
gemini skills install https://github.com/codewithmukesh/dotnet-claude-kit --path skills/vertical-sliceManually: put the files in place
.devin/skills/vertical-slice/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about vertical-slice
How do I install vertical-slice in Claude Code?
Run npx skills add codewithmukesh/dotnet-claude-kit --skill vertical-slice -a claude-code in your terminal.
What does vertical-slice do?
It provides architecture patterns for organizing .NET applications into self-contained vertical slices, grouping requests, handlers, validation, and endpoints by feature.
Which handler libraries does vertical-slice cover?
It covers source-generated Mediator with Native AOT support, Wolverine handlers matched by method convention, and plain C# handler classes with no external dependencies.
Source text
SKILL.md · MIT
---
name: vertical-slice
description: >
Vertical Slice Architecture (VSA) for .NET applications — one of several
supported architectures in dotnet-claude-kit. Covers feature folders, endpoint
grouping, and handler patterns for Mediator, Wolverine, and raw handler classes.
Load this skill when the architecture-advisor recommends VSA, when working in
an existing VSA codebase, when adding features to a feature-folder project,
or when discussing vertical slice patterns, feature folders, or handler patterns.
---
# Vertical Slice Architecture (VSA)
## Core Principles
1. **Organize by feature, not by layer** — Each feature is a self-contained vertical slice containing its endpoint, handler, request/response types, and validation. No more jumping between Controllers/, Services/, Repositories/ folders.
2. **Minimize cross-feature coupling** — Features should not reference each other directly. Shared concerns go in a `Common/` or `Shared/` directory.
3. **One file per feature is fine** — A simple CRUD endpoint doesn't need 5 files spread across layers. Start with everything in one file, extract only when complexity demands it.
4. **The handler is the unit of work** — Each handler does one thing. No god-services with 20 methods.
## Patterns
### Feature Folder Structure
```
src/
MyApp.Api/
Features/
Orders/
CreateOrder.cs # Request, Handler, Response, Endpoint — all in one file
GetOrder.cs
ListOrders.cs
CancelOrder.cs
Shared/
OrderMapper.cs # Shared within the Orders feature only
Products/
CreateProduct.cs
GetProduct.cs
Common/
Behaviors/
ValidationBehavior.cs # Cross-cutting Mediator pipeline behavior
Persistence/
AppDbContext.cs
Extensions/
ServiceCollectionExtensions.cs
Program.cs
```
### Pattern A: Mediator Handlers (Recommended Default)
Source-generated mediator — MIT licensed, no reflection, Native AOT compatible. Uses `IRequest<T>` / `IRequestHandler<TRequest, TResponse>` with pipeline behaviors. Near-identical API to MediatR but faster and free. Package: `Mediator.Abstractions` + `Mediator.SourceGenerator`.
```csharp
// Features/Orders/CreateOrder.cs
public static class CreateOrder
{
public record Command(string CustomerId, List<OrderItemDto> Items) : IRequest<Result<OrderResponse>>;
public record OrderItemDto(string ProductId, int Quantity);
public record OrderResponse(Guid Id, decimal Total, DateTime CreatedAt);
public class Validator : AbstractValidator<Command>
{
public Validator()
{
RuleFor(x => x.CustomerId).NotEmpty();
RuleFor(x => x.Items).NotEmpty();
RuleForEach(x => x.Items).ChildRules(item =>
{
item.RuleFor(x => x.ProductId).NotEmpty();
item.RuleFor(x => x.Quantity).GreaterThan(0);
});
}
}
internal sealed class Handler(AppDbContext db, TimeProvider clock) : IRequestHandler<Command, Result<OrderResponse>>
{
public async ValueTask<Result<OrderResponse>> Handle(Command request, CancellationToken ct)
{
var order = Order.Create(request.CustomerId, request.Items, clock.GetUtcNow());
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
return Result.Success(new OrderResponse(order.Id, order.Total, order.CreatedAt));
}
}
}
// Registration in Program.cs or module DI
builder.Services.AddMediator();
// Features/Orders/OrderEndpoints.cs — auto-discovered via IEndpointGroup
public sealed class OrderEndpoints : IEndpointGroup
{
public void Map(IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/orders").WithTags("Orders");
group.MapPost("/", async (CreateOrder.Command command, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(command, ct);
return result.IsSuccess
? TypedResults.Created($"/api/orders/{result.Value.Id}", result.Value)
: result.ToProblemDetails();
})
.WithName("CreateOrder").Produces<CreateOrder.OrderResponse>(201)
.ProducesValidationProblem()
.AddEndpointFilter<ValidationFilter<CreateOrder.Command>>();
}
}
```
### Pattern B: Wolverine Handlers
Convention-based — no interfaces to implement. Wolverine discovers handlers by method signature.
```csharp
// Features/Orders/CreateOrder.cs
public static class CreateOrder
{
public record Command(string CustomerId, List<OrderItemDto> Items);
public record OrderItemDto(string ProductId, int Quantity);
public record OrderResponse(Guid Id, decimal Total, DateTime CreatedAt);
// Wolverine discovers this by convention (static Handle method)
public static async Task<Result<OrderResponse>> Handle(
Command command,
AppDbContext db,
TimeProvider clock,
CancellationToken ct)
{
var order = Order.Create(command.CustomerId, command.Items, clock.GetUtcNow());
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
return Result.Success(new OrderResponse(order.Id, order.Total, order.CreatedAt));
}
}
```
### Pattern C: Raw Handler Classes (No Library)
Direct handler classes with no external dependency. Good for small projects or teams that want full control.
```csharp
// Features/Orders/CreateOrder.cs
public static class CreateOrder
{
public record Command(string CustomerId, List<OrderItemDto> Items);
public record OrderItemDto(string ProductId, int Quantity);
public record OrderResponse(Guid Id, decimal Total, DateTime CreatedAt);
internal class Handler(AppDbContext db, TimeProvider clock)
{
public async Task<Result<OrderResponse>> ExecuteAsync(Command command, CancellationToken ct)
{
var order = Order.Create(command.CustomerId, command.Items, clock.GetUtcNow());
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
return Result.Success(new OrderResponse(order.Id, order.Total, order.CreatedAt));
}
}
}
// Endpoint wiring — Result maps to HTTP response
group.MapPost("/", async (CreateOrder.Command command, CreateOrder.Handler handler, CancellationToken ct) =>
{
var result = await handler.ExecuteAsync(command, ct);
return result.IsSuccess
? TypedResults.Created($"/api/orders/{result.Value.Id}", result.Value)
: result.ToProblemDetails();
});
```
### Adding Module Boundaries (Optional)
For larger applications that grow beyond a single project, introduce module boundaries. Each module is a separate class library with its own features and DbContext.
```
src/
MyApp.Api/ # Host — wires modules together
Program.cs
Modules/
ModuleExtensions.cs # app.MapOrderModule(), app.MapCatalogModule()
MyApp.Orders/ # Module — own features, own DbContext
Features/
CreateOrder.cs
Persistence/
OrdersDbContext.cs
OrdersModule.cs # IServiceCollection + IEndpointRouteBuilder extensions
MyApp.Catalog/ # Module
Features/
CreateProduct.cs
Persistence/
CatalogDbContext.cs
CatalogModule.cs
```
Modules communicate via:
- **Integration events** (preferred) — async, decoupled via Wolverine or MassTransit
- **Shared contracts** — a `MyApp.Contracts` project with DTOs/interfaces (use sparingly)
### Shared Concerns
Cross-cutting concerns live outside feature folders:
```csharp
// Common/Behaviors/ValidationBehavior.cs (Mediator pipeline)
public sealed class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : IMessage
{
public async ValueTask<TResponse> Handle(
TRequest request,
MessageHandlerDelegate<TRequest, TResponse> next,
CancellationToken ct)
{
var context = new ValidationContext<TRequest>(request);
var failures = validators
.Select(v => v.Validate(context))
.SelectMany(r => r.Errors)
.Where(f => f is not null)
.ToList();
if (failures.Count > 0)
throw new ValidationException(failures);
return await next(request, ct);
}
}
```
## Anti-patterns
### Don't Create Layered Abstractions Within a Slice
```csharp
// BAD — a feature folder with its own service layer and repository
Features/
Orders/
CreateOrder.cs
IOrderService.cs # unnecessary abstraction
OrderService.cs # unnecessary abstraction
IOrderRepository.cs # unnecessary abstraction
OrderRepository.cs # unnecessary abstraction
// GOOD — handler talks directly to DbContext
Features/
Orders/
CreateOrder.cs # handler uses AppDbContext directly
```
### Don't Cross-reference Features Directly
```csharp
// BAD — CreateOrder directly calls GetProduct handler
var product = await _getProductHandler.Handle(new GetProduct.Query(productId));
// GOOD — query the database directly or use a shared read model
var product = await db.Products.FindAsync(productId, ct);
```
### Don't Put Everything in One God Feature File
```csharp
// BAD — 500-line file with CRUD + business logic + mapping
public static class Orders
{
// Create, Read, Update, Delete, Cancel, Refund, Export...
}
// GOOD — one file per operation
Features/Orders/CreateOrder.cs
Features/Orders/GetOrder.cs
Features/Orders/CancelOrder.cs
```
## Decision Guide
| Scenario | Recommendation |
|----------|---------------|
| New project (default) | Pattern A — Mediator (source-generated, MIT, fast) |
| Need mediator + messaging in one lib | Pattern B — Wolverine (also handles events/queues) |
| Want full control, no dependencies | Pattern C — Raw handler classes |
| Existing MediatR codebase with license | Keep MediatR if licensed; otherwise migrate to Mediator (near-identical API) |
| Monolith growing complex | Add module boundaries, keep VSA within each module |
| Simple CRUD feature | Single file: request + handler + endpoint |
| Complex feature (saga, events) | Multiple files in feature folder, still colocated |
| Sharing logic between features | Extract to `Common/` — not to another feature |
© codewithmukesh · MIT · codewithmukesh/dotnet-claude-kit
Similar skills
Everything for Backend and APIs →vertical-slice by other authors comes first.