Vertical Slice Architecture is the organizing principle behind every Indotalent product, and this guide is the definitive starting point for .NET developers who want to master it. Instead of arranging code into technical layers such as Controllers, Services, Repositories, and DTOs, Vertical Slice Architecture groups everything a single business feature needs into one self-contained slice. The result is code that is easier to read, easier to test, and dramatically easier to extend over the lifetime of an application.
What Is Vertical Slice Architecture?
At its core, Vertical Slice Architecture is a simple rule: when you change a behavior, you should only touch code that belongs to that behavior. A slice captures one end-to-end scenario, from the HTTP request that arrives at your API down to the database write that completes it. The concept was popularized in the .NET community by Jimmy Bogard and has since become the default structure for new .NET 10 applications built with Minimal APIs and MediatR.
The contrast with layered architecture could not be sharper. In a classic n-tier layout, a single feature like "Create Order" is smeared across Controllers/, Services/, Repositories/, Domain/, and DTOs/ — often in five separate projects. Every feature change touches the same five folders, which is why teams see merge conflicts on files they never consciously work on together. VSA eliminates that friction by giving each feature its own vertical strip.
The Vertical Slice Architecture Feature Folder Pattern
The most common implementation is the feature folder. Each folder under Features/ represents one capability of your application, and inside the folder you keep everything that capability needs and nothing else. A typical tree looks like this:
/Features
/Orders
/CreateOrder
CreateOrderCommand.cs
CreateOrderHandler.cs
CreateOrderResponse.cs
CreateOrderValidator.cs
/GetOrder
GetOrderQuery.cs
GetOrderHandler.cs
/CancelOrder
CancelOrderCommand.cs
CancelOrderHandler.cs
/Customers
/RegisterCustomer
RegisterCustomerCommand.cs
RegisterCustomerHandler.cs
There is no Controllers folder and no Services folder anywhere in this tree. When the product owner says "change the validation on order creation," you open one folder. When a new developer joins, they can enumerate every behavior of the system by reading folder names alone. Name each slice after the business action it performs — CreateOrder, GetOrder, CancelOrder — and the project map reads like the product backlog.
One Slice, One File: Minimal APIs and MediatR
In .NET 10, you can go a step further and collapse an entire slice into a single file using a Minimal API route and a MediatR handler. The endpoint is a thin adapter that receives the HTTP request, maps it to a command, and lets the handler do the real work. Here is a complete "Create Order" slice:
// Features/Orders/CreateOrder.cs
public static class CreateOrder
{
public static void Map(this RouteGroupBuilder group) =>
group.MapPost("/", async (CreateOrderCommand cmd, IMediator mediator) =>
{
var result = await mediator.Send(cmd);
return Results.Created($"/api/orders/{result.Id}", result);
});
}
public sealed record CreateOrderCommand(
string CustomerId, List<OrderItem> Items) : IRequest<OrderDto>;
public sealed class CreateOrderHandler(AppDbContext db)
: IRequestHandler<CreateOrderCommand, OrderDto>
{
public async Task<OrderDto> Handle(
CreateOrderCommand cmd, CancellationToken ct)
{
var order = Order.Create(cmd.CustomerId, cmd.Items);
db.Orders.Add(order);
await db.SaveChangesAsync(ct);
return OrderDto.FromEntity(order);
}
}
The endpoint, the command, and the handler all live in one file. To add a new behavior, you add a new file and register it in a route group. There is no ripple of changes across five projects, because a slice does not depend on other slices. When the slice grows past a few hundred lines, promote it from one file to a folder — the same pattern, just more files.
CQRS Emerges Naturally
An underrated benefit is that CQRS falls out of VSA with zero effort. Commands handle writes, queries handle reads, and each is a tiny class implementing IRequest. Because read paths and write paths are already separate slices, you can optimize them independently: cache a query, denormalize for a dashboard, or move a heavy read to raw SQL without disturbing a single command slice.
Pitfalls That Break Vertical Slice Architecture
VSA is simple, but it is easy to abuse. Teams that drop a Repository and Service layer back on top of their slices end up with the worst of both worlds — all the ceremony of layers, none of the cohesion of slices. Watch for these mistakes:
- Premature abstraction: creating interfaces for every handler nobody ever mocks, which adds ceremony without value.
- Coupling slices through a god object: a shared mega-entity that forces slices to reach into each other's internals.
- Copy-pasted validation: duplicating the same rules in ten slices instead of extracting one shared component.
- Skipping cross-cutting concerns: forgetting that logging, caching, and authorization still need consistent handling even when code lives in slices.
None of these mistakes are fatal, but all of them erode the cohesion that makes Vertical Slice Architecture valuable. Keep slices independent, keep shared abstractions minimal, and revisit the structure whenever a change starts to touch more than one feature folder.
FAQ
Is Vertical Slice Architecture the same as CQRS?
No, but they pair extremely well. VSA is a structural pattern for organizing code by feature, while CQRS separates writes from reads. MediatR delivers both at once, which is why the two are almost always discussed together in .NET 10 projects.
Do I still need Repository and Service layers with VSA?
No. The DbContext and your business logic live inside the slice. A Repository is only useful when you need to abstract a data source that genuinely varies, which is rare in a single-database application.
Can Vertical Slice Architecture work in a large monolith?
Yes — it is the recommended shape for a modular monolith. Features stay independent and testable while the deployment remains a single process, and you can later lift individual slices into microservices if a feature outgrows the monolith.
Where do shared components like the DbContext live?
Shared infrastructure lives in a common project that slices reference. The reverse is never true — a slice is the dependency root for its own behavior and should never be referenced by other features.
Key Takeaways
- Vertical Slice Architecture organizes code by business capability, not technical concern
- Feature folders make features discoverable and changes local
- .NET 10 Minimal APIs plus MediatR handlers keep each slice concise and testable
- Avoid stacking Repository and Service abstractions back on top of slices
- Every Indotalent product ships as a complete Vertical Slice Architecture codebase for $21