Vertical Slice Architecture in .NET: The Easy Guide
Learn Vertical Slice Architecture in .NET in simple words. Organise code by feature instead of by layer, with diagrams, real examples, a comparison with Clean Architecture, and when to use each.
A cake cut two different ways
Imagine a cake with several layers — sponge, cream, jam, and icing.
There are two ways to cut it. You could cut it horizontally, separating all the sponge from all the cream from all the jam. Now each plate has only one layer. To enjoy a proper bite, you would have to gather a piece from every plate and stack them yourself.
Or you could cut it vertically, like a normal slice. Each slice already has all the layers together — sponge, cream, jam, and icing in one piece. One slice is a complete, ready-to-eat bite.
This is exactly the difference between two ways of organising code. The horizontal cut is layered architecture (including Clean Architecture): all the controllers in one place, all the services in another, all the data access in a third. The vertical cut is Vertical Slice Architecture (VSA): everything a single feature needs lives together in one slice.
Let us see why slicing vertically often makes life easier, and when it does not.
The problem with horizontal layers
In a layered app, the code for one feature is scattered across many folders. To add a simple "Create Order" feature, you typically touch:
- a Controller (in the API layer)
- a Service (in the Application layer)
- a Repository (in the Infrastructure layer)
- maybe a DTO, a validator, and a mapping profile in yet more folders
Nothing here is wrong on its own. But notice the pain: to understand or change one feature, you open five folders, and each of those folders is full of unrelated code from other features. The shared service and repository keep growing as every feature piles into them. Over time these shared layers become crowded and risky to touch — a change for one feature can accidentally break another.
The vertical slice idea
VSA cuts the other way. Instead of grouping by what kind of code it is (controller, service, repository), you group by which feature it belongs to. Each feature becomes a self-contained slice holding everything it needs.
Now, to work on "Create Order," you open one folder. Everything is right there. You build, test, and ship the feature without wading through shared layers. As Jimmy Bogard — who popularised VSA in the .NET world — puts it, you minimise the number of things you must touch to make a change, and you keep things that change together close together.
Layered vs Vertical Slice
Steps
Layered
Controllers, services, repositories in separate layers
Scattered
One feature lives in many folders at once
Sliced
Group everything for a feature together
Whole
Change a feature by touching one place
What a slice looks like in .NET
A slice is usually a single folder per feature. Inside it sits the request, the response, the handler with the logic, and the endpoint. Here is a clean folder layout:
Features/
├── Orders/
│ ├── CreateOrder/
│ │ ├── CreateOrderEndpoint.cs
│ │ ├── CreateOrderHandler.cs
│ │ └── CreateOrderRequest.cs
│ ├── GetOrder/
│ │ ├── GetOrderEndpoint.cs
│ │ └── GetOrderHandler.cs
│ └── CancelOrder/
│ ├── CancelOrderEndpoint.cs
│ └── CancelOrderHandler.csAnd a single slice in code might look like this — endpoint and handler living together, using a minimal API so no extra library is needed:
// CreateOrder/CreateOrderRequest.cs
public record CreateOrderRequest(Guid CustomerId, List<OrderItem> Items);
// CreateOrder/CreateOrderHandler.cs
public class CreateOrderHandler(AppDbContext db)
{
public async Task<Guid> Handle(CreateOrderRequest request, CancellationToken ct)
{
var order = Order.Create(request.CustomerId, request.Items);
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
return order.Id;
}
}
// CreateOrder/CreateOrderEndpoint.cs
public static class CreateOrderEndpoint
{
public static void Map(IEndpointRouteBuilder app) =>
app.MapPost("/orders", async (
CreateOrderRequest request,
CreateOrderHandler handler,
CancellationToken ct) =>
{
var id = await handler.Handle(request, ct);
return Results.Created($"/orders/{id}", new { id });
});
}Everything about creating an order is in one folder. A new developer can read this slice top to bottom and understand the whole feature without opening anything else.
MediatR is the library that made vertical slices famous, turning each feature into a command/query plus a handler. It is now commercially licensed, so for new projects you can use plain handler classes (as above), minimal APIs, or free alternatives. The architecture does not depend on any single tool.
Vertical Slice vs Clean Architecture
These are often presented as rivals, but they answer different questions. Clean Architecture is about dependency direction (inner business rules must not depend on outer details). Vertical Slice is about code organisation (group by feature). Here is the comparison:
| Clean Architecture | Vertical Slice | |
|---|---|---|
| Cuts code by | Technical layer (Domain, App, Infra, API) | Feature (CreateOrder, GetOrder…) |
| To change a feature | Touch many layers | Touch one slice |
| Shared code | Lots, in shared layers | Little; some duplication is allowed |
| Best at | Enforcing strict dependency rules | Fast feature work, easy navigation |
| Risk | Ceremony and folder-hopping | Slices can drift in style without guidelines |
Notice the row about duplication. VSA happily allows a little duplication between slices to avoid the "wrong abstraction." Two features that look similar today might need to change differently tomorrow; keeping them separate makes that easy. Clean Architecture instead pushes shared logic into common layers.
You do not have to choose only one. A common, powerful setup is to use Clean Architecture's project layers for dependency rules, and organise the application layer by feature slices inside it. You get strict dependencies and feature-first navigation.
What goes inside one slice
It helps to see the parts of a single slice laid out. A well-formed slice usually has four small pieces that work together:
Anatomy of a Vertical Slice
Steps
Request
The input data for this feature (a record/DTO)
Endpoint
Maps the HTTP route to the handler
Handler
The actual business logic and data access
Response
What the feature returns to the caller
Handling cross-cutting concerns
A fair question: if each slice is independent, how do you handle things every feature needs — like validation, logging, and error handling — without copying them into every slice?
The answer is a small shared pipeline or wrapper that runs around your handlers. You write the concern once and apply it to all slices, while the slice itself stays focused on its own job. For example, validation can live in a tiny reusable step:
// A reusable validation step, shared by every slice that needs it.
public static class ValidationBehavior
{
public static async Task<IResult> Validate<T>(
T request, IValidator<T> validator, Func<Task<IResult>> next)
{
var result = await validator.ValidateAsync(request);
if (!result.IsValid)
return Results.ValidationProblem(result.ToDictionary());
return await next(); // valid → run the slice's handler
}
}Each slice still owns its own logic, but shared concerns like validation, logging, and authorization are written once and reused. This keeps slices small without duplicating the boring plumbing. The key is balance: share the generic plumbing, but keep the feature-specific logic inside the slice.
A simple guideline: if a piece of code is about how the app works in general (logging, validation, error formatting), share it in a pipeline. If it is about what this feature does (how an order is created), keep it inside the slice. This line keeps slices clean without over-sharing.
A common misunderstanding
Just putting controllers and views in feature folders does not make your backend vertically sliced. And using a request/handler library does not automatically slice your code either. If your handlers still call into big shared services and repositories that every feature depends on, you have layered code wearing a slice costume.
True vertical slicing means each slice can do its own work — including its own data access — without being forced through shared layers. A little independence per slice is the whole point.
Another sign of healthy slices: you can read one feature from top to bottom without opening any other file. If understanding "Create Order" forces you to jump into a giant shared service that also serves twenty other features, the slice is leaking. Keep the path from request to response short and contained, and your slices stay easy to read, test, and change on their own.
When to use Vertical Slice Architecture
VSA is a great fit when:
- Your app has many distinct features (most real business apps do).
- You want teams to work in parallel without colliding in shared layers.
- You value fast onboarding — new developers learn one slice at a time.
- You are building a modular monolith, where slices group naturally into modules.
It is less necessary for:
- Very small apps with only a handful of endpoints, where simple layering is already easy to navigate.
- Pure library or domain code with no features to slice in the first place.
| Choose… | When… |
|---|---|
| Vertical Slice | Feature-rich apps, parallel teams, fast iteration |
| Plain layering | Tiny apps, prototypes |
| Clean + Slices | You need strict dependency rules and feature-first code |
Quick recap
- Vertical Slice Architecture organises code by feature, not by technical layer — like cutting a cake into whole slices instead of separating the layers.
- Each slice keeps its endpoint, logic, and data access together, so you change a feature by touching one place.
- It avoids the crowded, risky shared layers of pure layered architecture, and even allows a little duplication to dodge the wrong abstraction.
- It pairs beautifully with the modular monolith, and can be combined with Clean Architecture for strict dependencies plus feature-first code.
- MediatR popularised it but is now commercial — the pattern works fine with plain handlers or minimal APIs.
Cut your code into whole slices, keep each feature self-contained, and your codebase becomes a tray of ready-to-eat pieces instead of a stack of separated layers you must assemble every time. The payoff shows up every day: features are faster to build, easier to read, simpler to test, and safer to change — because each one lives in a single, clear place that you can understand on its own.
References and further reading
- Vertical Slice Architecture — Jimmy Bogard — from the developer who popularised the approach in .NET.
- Vertical Slice Architecture in ASP.NET Core — Code Maze — a hands-on .NET walkthrough.
- N-Layered vs Clean vs Vertical Slice Architecture — Anton Martyniuk — a clear comparison of the three approaches.
Related Posts
What Is a Modular Monolith? A Beginner-Friendly Guide for .NET
Understand the modular monolith in simple words: one app, strong internal walls. Learn how it compares to monoliths and microservices, why it is the 2026 default for most .NET teams, and how to build one.
Clean Architecture Folder Structure in .NET: A Simple Guide
Learn how to organise a .NET solution with Clean Architecture. Understand the Domain, Application, Infrastructure, and Presentation layers, the dependency rule, and the exact folders, with diagrams and examples.
N-Layered vs Clean vs Vertical Slice Architecture in .NET
A simple, friendly guide comparing N-layered, Clean, and Vertical Slice architecture in .NET, with diagrams, code, tables, and clear advice on when to pick each one.
Where Vertical Slices Fit Inside the Modular Monolith
A simple guide to how vertical slices live inside the modules of a modular monolith in .NET, with diagrams, code, tables, and everyday examples.
Screaming Architecture in .NET: Let Your Folders Tell the Story
Learn Screaming Architecture in .NET in plain words. Make your folder structure shout the business purpose, not the framework, with diagrams and real examples.
The Best Way to Structure .NET Projects: Clean Architecture + Vertical Slices
A friendly guide to structuring .NET projects by mixing Clean Architecture with Vertical Slices, with diagrams, code, tables, and simple, beginner-ready advice.