When to Choose Vertical Slice Architecture Over Layered Architecture

When to Choose Vertical Slice Architecture Over Layered Architecture

6 min read··

dotnetsoftware-architecturevertical-slice-architecture

Choose Vertical Slice Architecture when your features are mostly independent, the application is CRUD-heavy, you want fast iteration with minimal ceremony, or your team works on many features in parallel. Layers still win when many features share complex business logic or you need strict compile-time boundaries. Here are the concrete signals for each, and what to do when they point both ways.

Layered architecture is the default choice in .NET, and defaults rarely get questioned. But an architecture you picked by inertia is still an architecture decision, just one made without looking at the alternatives.

The Problem With Layers

In a layered architecture, a simple "Get Order by ID" feature touches:

  1. OrdersController (Presentation)
  2. IOrderService + OrderService (Application)
  3. IOrderRepository + OrderRepository (Infrastructure)
  4. OrderDto, OrderResponse (Mapping)

Four files across four folders for a database query that returns one object. Adding a new feature means touching every layer. Modifying a feature means jumping between folders.

What Changes Together Should Live Together

Vertical Slice Architecture organizes code by feature instead of layer, and it's easier to adopt than most people think:

// Layered: related code is scattered
Controllers/OrdersController.cs    ← GetOrder, CreateOrder, DeleteOrder
Services/OrderService.cs           ← GetOrder, CreateOrder, DeleteOrder
Repositories/OrderRepository.cs    ← GetOrder, CreateOrder, DeleteOrder

// VSA: related code is co-located
Features/Orders/GetOrder.cs        ← everything for GetOrder
Features/Orders/CreateOrder.cs     ← everything for CreateOrder
Features/Orders/DeleteOrder.cs     ← everything for DeleteOrder

When you work on "Get Order," you open one file. When you review a pull request, the diff shows one file per feature.

When to Choose VSA

Your Features Are Independent

If most features don't share logic, VSA reduces unnecessary abstractions:

// This feature needs no repository, no service layer
public static class GetOrder
{
    public sealed record Query(Guid Id);

    public sealed record OrderResponse(
        Guid Id, string Status, decimal TotalAmount, DateTime CreatedAt);

    public sealed class Handler(ApplicationDbContext db)
    {
        public async Task<OrderResponse?> Handle(
            Query query, CancellationToken ct)
        {
            return await db.Orders
                .Where(o => o.Id == query.Id)
                .Select(o => new OrderResponse(
                    o.Id, o.Status, o.TotalAmount, o.CreatedAt))
                .FirstOrDefaultAsync(ct);
        }
    }
}

No interface, no repository, no service. Just a query that returns data.

Your Team Is Growing

With layers, two developers working on separate features often edit the same files - the same controller, the same service. Merge conflicts happen frequently.

With VSA, each developer works in separate files. Feature A doesn't touch Feature B's code.

You Want Fast Iteration

VSA has less ceremony. Adding a new feature:

  1. Create one file
  2. Define the request, handler, and endpoint
  3. Done

No interface to define, no repository to implement, and assembly scanning handles the registration.

Your Application Is CRUD-Heavy

Many business applications are variations of create-read-update-delete. VSA handles this cleanly:

Features/
  Products/
    CreateProduct.cs      ← 60 lines
    GetProduct.cs         ← 40 lines
    GetProducts.cs        ← 50 lines
    UpdateProduct.cs      ← 70 lines
    DeleteProduct.cs      ← 30 lines

Each file is small and self-contained. No layered abstractions adding complexity without value.

You're Using CQRS

CQRS and VSA are a natural pair. Commands and queries are already separate operations - putting each in its own file is the logical next step:

Features/
  Orders/
    Commands/
      PlaceOrder.cs
      CancelOrder.cs
    Queries/
      GetOrder.cs
      GetOrders.cs

When to Choose Layers

You Have Complex Shared Business Logic

If 10 features all need the same pricing calculation, a PricingService in a service layer makes sense. Duplicating that logic across 10 slices is worse.

You Need Strict Architectural Boundaries

Layers enforce compile-time boundaries. The presentation layer physically cannot reference the database. VSA in a single project doesn't prevent a handler from doing whatever it wants.

Your Team Is Familiar With Layers

Architecture decisions are team decisions. If your team knows layered architecture well and productivity is good, switching to VSA for the sake of switching creates churn without value.

You Have a Rich Domain Model

Domain-Driven Design with a rich domain model benefits from a dedicated domain layer. The domain layer contains complex business rules that multiple features share. Clean Architecture is a better fit here.

The Middle Ground

You don't have to be all-in on either approach. Many successful projects combine both:

src/
  MyApp.Api/
    Features/           ← Vertical slices for individual operations
      Orders/
        PlaceOrder.cs
        GetOrder.cs
    Domain/             ← Shared domain entities (from Clean Architecture)
      Order.cs
      Customer.cs
    Shared/             ← Cross-cutting concerns
      Behaviors/
        ValidationBehavior.cs

Use slices for application logic. Use a domain layer for shared business rules. Use pipeline behaviors for cross-cutting concerns.

Migrating From Layers, Incrementally

Choosing VSA doesn't mean rewriting your layered application. The migration path I recommend:

  1. New features go in a Features folder as self-contained slices. Don't touch the existing layers yet.
  2. When you modify an existing feature, consider moving it into a slice as part of the change. The controller action, service method, and repository method collapse into one handler.
  3. Leave stable code alone. A feature nobody has touched in a year gains nothing from being restructured.
  4. Delete layers as they empty out. When OrderService has one method left, inline it and remove the class.

After a few months you have a codebase that's mostly slices with a small legacy core, and you got there without a big-bang rewrite or a feature freeze.

Decision Matrix

A decision flow: rich shared domain logic or strict compile-time boundaries point to layered or Clean Architecture; independent, CRUD-heavy, or CQRS features point to vertical slices, otherwise a hybrid

Signals that point toward Vertical Slice Architecture:

  • Features are largely independent of each other
  • The application is CRUD-heavy
  • You need fast iteration with minimal ceremony
  • The team is growing and works on many features in parallel
  • You're already using CQRS

Signals that point toward layers:

  • Heavy shared business logic across features
  • A rich domain model with DDD
  • You need strict compile-time boundaries
  • The team is experienced and productive with layers

If your signals land on both sides, that's normal. It usually means the hybrid approach (slices plus a shared domain layer) is your answer.

Summary

Choose Vertical Slice Architecture when:

  1. Features are independent and rarely share logic
  2. Your team needs parallel development without merge conflicts
  3. You value simplicity - one file per feature, no unnecessary abstractions
  4. You're already using CQRS (with or without MediatR)
  5. The application is CRUD-heavy without complex domain logic

Choose layers when shared business logic, strict boundaries, or DDD richness justifies the overhead.

The best architecture is the one your team can maintain and evolve. Start with what fits your problem, not what's trending.

Thanks for reading, and stay awesome!


Frequently Asked Questions

When should you use Vertical Slice Architecture?

When features are mostly independent, the application is CRUD-heavy or varied in complexity, you want fast iteration with minimal ceremony, and your team benefits from working in parallel without merge conflicts. CQRS-based apps map onto slices especially well.

When is layered architecture the better choice?

When many features share complex business logic, you need compile-time boundaries between layers, or you are building a rich domain model with DDD. A dedicated domain layer earns its keep when rules are shared across many use cases.

Is Vertical Slice Architecture good for large projects?

Yes, if you group slices by domain area as the feature count grows. Large codebases often combine slices for application logic with a shared domain layer for business rules.

Does Vertical Slice Architecture work without MediatR?

Yes. The pattern is about organizing code by feature, not about any library. Minimal API endpoints calling plain handler classes achieve the same result.

Loading comments...

Whenever you're ready, there are 4 ways I can help you:

  1. Pragmatic Clean Architecture: Join 5,000+ students in this comprehensive course that will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture.
  2. Modular Monolith Architecture: Join 2,800+ engineers in this in-depth course that will transform the way you build modern systems. You will learn the best practices for applying the Modular Monolith architecture in a real-world scenario.
  3. Pragmatic REST APIs: Join 1,900+ students in this course that will teach you how to build production-ready REST APIs using the latest ASP.NET Core features and best practices. It includes a fully functional UI application that we'll integrate with the REST API.
  4. Patreon Community: Join a community of 5,000+ engineers and software architects. You will also unlock access to the source code I use in my YouTube videos, early access to future videos, and exclusive discounts for my courses.

The .NET Weekly

Become a Better .NET Software Engineer

Join 66,000+ engineers who are improving their skills every Saturday morning.