Vertical Slice Architecture
Organizes code by feature instead of by layer: each slice contains Web + App + Domain + Infra components for a specific functionality.
Context
In layered architectures, adding a feature requires touching 5 different folders. Cohesion is broken.
Solution
Each feature is organized in its own folder and contains EVERYTHING it needs: endpoint, validator, handler, query, events.
Features/
├── Orders.Place/
│ ├── PlaceOrderCommand.cs
│ ├── PlaceOrderHandler.cs
│ ├── PlaceOrderValidator.cs
│ └── PlaceOrderEndpoint.cs
└── Orders.Cancel/
├── CancelOrderCommand.cs
├── CancelOrderHandler.cs
└── CancelOrderEndpoint.cs
#C# Example
// Features/Orders.Place/PlaceOrderEndpoint.cs
public class PlaceOrderEndpoint
{
public static void Map(IEndpointRouteBuilder app) =>
app.MapPost("/orders", async (PlaceOrderCommand cmd, IMediator m) =>
Results.Ok(await m.Send(cmd)));
}
public record PlaceOrderCommand(Guid CustomerId, decimal Total) : IRequest<Guid>;
public class PlaceOrderValidator : AbstractValidator<PlaceOrderCommand>
{
public PlaceOrderValidator() => RuleFor(x => x.Total).GreaterThan(0);
}
public class PlaceOrderHandler : IRequestHandler<PlaceOrderCommand, Guid>
{
public Task<Guid> Handle(PlaceOrderCommand req, CancellationToken ct) => /* ... */;
}When NOT to use it
- When there are huge domain invariants that cross slices: you need an explicit domain (Clean / DDD).
Tradeoffs
| Pro | Con |
|---|---|
| High cohesion per feature | Risk of duplicating code between slices |
| Fast onboarding | Without discipline, features become entangled |
#architecture #feature-folder