When I started building microservices in .NET my natural instinct was to follow the traditional layered architecture. Controllers at the top then services then repositories. This felt familiar and clean at first. But as the project grew I started to notice friction. Small changes required touching multiple layers. Features were scattered across folders. Understanding the full flow of a single use case took time.
While working on this project I learned and applied Vertical Slice Architecture. This approach changed how I think about designing microservices.
Layered architecture vs vertical slices
In layered architecture we organize code by technical concerns. Controllers go in one folder. Services in another. Data access somewhere else. This looks neat but a single business feature is split across many places.
In Vertical Slice Architecture we organize code by features. Each feature owns everything it needs. Request model handler validation mapping and endpoint live together. If I want to understand or change a feature I only look at one place.
This difference sounds small but the impact is big.
How vertical slices reduce coupling
In layered systems controllers depend on services and services depend on repositories. Over time these services become shared by many features. A small change for one feature risks breaking another. This creates tight coupling.
With vertical slices each feature has its own flow. A feature talks directly to what it needs. Other features are not affected. There is no shared service layer that slowly turns into a god class.
In my project this made changes safer and faster. I could add or modify a feature without worrying about side effects.
Role of MediatR
MediatR played a key role in enabling this style. Each feature is expressed as a command or a query. The handler contains the business logic for that use case.
There is no controller calling multiple services. The endpoint sends a request and the handler does the work. This makes the flow explicit and easy to follow.
It also helped me add cross cutting concerns like validation and logging without polluting business code.
Role of Carter
Carter helped keep endpoints minimal and feature focused. Instead of large controllers with many actions each feature defines its own endpoint.
Endpoint definition request and response stay close to the handler. This matches the idea of a vertical slice very well.
As a result my API surface became easier to read and easier to maintain.
Why modern .NET microservices prefer this approach
Modern microservices favor changeability over perfect abstraction. Vertical slices optimize for change. Features are isolated. Code is easier to reason about. New developers can onboard faster.
In this project I felt that benefit directly. Debugging became simpler. Refactoring felt safer. The codebase stayed organized even as features increased.
What I learned
Vertical Slice Architecture is not about new tools. It is about aligning code with business use cases. MediatR and Carter are enablers not the goal.
If you are building microservices in .NET and feel friction with controllers and service layers this approach is worth trying. It changed how I design systems and how confidently I evolve them.