Structure a Vertical Slice Architecture project around a Features folder with one file per use case, plus a Domain folder for shared entities, Data for EF Core infrastructure, and Shared for cross-cutting behaviors.
One project is enough to start, and grouping by domain area keeps the layout manageable past 50 features.
Vertical Slice Architecture sounds simple until you create the solution and have to decide where everything goes. Where do domain entities live? Does the DbContext get its own project? This article answers those questions with a concrete layout, and shows how it evolves as the project grows.
The Problem With Layered Folders
In a traditional layered project, you get folders like this:
Controllers/
OrdersController.cs
CustomersController.cs
ProductsController.cs
Services/
OrderService.cs
CustomerService.cs
ProductService.cs
Repositories/
OrderRepository.cs
CustomerRepository.cs
ProductRepository.cs
Models/
Order.cs
Customer.cs
Product.cs
To understand how "Place Order" works, you jump between 4+ folders. Adding a feature means touching multiple folders. Related code is scattered.
Vertical Slice Architecture fixes this by organizing code around features. This article is about the practical part: the actual folder and solution layout, and how it holds up as the feature count grows.
For what goes inside a slice (the command, handler, and validator structure), see my newsletter issue on structuring vertical slices. Here we stay at the folder level.
The Starting Layout: 5-15 Features
One project, one Features folder, one file per use case:
Features/
Orders/
PlaceOrder.cs
GetOrder.cs
GetOrders.cs
CancelOrder.cs
OrdersModule.cs
Customers/
RegisterCustomer.cs
GetCustomer.cs
UpdateCustomer.cs
CustomersModule.cs
Products/
CreateProduct.cs
GetProducts.cs
SearchProducts.cs
ProductsModule.cs
Everything for "Place Order" is in one file. Everything for orders is in one folder. The *Module.cs file per folder registers that feature group's endpoints (a Carter module or a plain extension method, your choice).
Two naming rules keep this navigable:
- Files are verbs:
PlaceOrder.cs, notOrderService.cs. The folder listing reads like a feature list. - One use case per file: if a file handles two operations, it's two slices pretending to be one.
Full Project Structure
Here's the complete single-project layout I use:
src/
MyApp.Api/
Features/
Orders/
PlaceOrder.cs
GetOrder.cs
GetOrders.cs
CancelOrder.cs
UpdateOrderStatus.cs
OrdersModule.cs
Customers/
RegisterCustomer.cs
GetCustomer.cs
GetCustomers.cs
UpdateCustomer.cs
CustomersModule.cs
Products/
CreateProduct.cs
GetProducts.cs
SearchProducts.cs
ProductsModule.cs
Domain/
Order.cs
Customer.cs
Product.cs
Common/
Entity.cs
Result.cs
Error.cs
Data/
ApplicationDbContext.cs
Configurations/
OrderConfiguration.cs
CustomerConfiguration.cs
ProductConfiguration.cs
Migrations/
Shared/
Behaviors/
ValidationBehavior.cs
LoggingBehavior.cs
Middleware/
ExceptionHandlingMiddleware.cs
Program.cs
tests/
MyApp.Api.Tests/
Features/
Orders/
PlaceOrderTests.cs
GetOrderTests.cs
Customers/
RegisterCustomerTests.cs
Note that the test project mirrors the Features tree exactly. Finding the tests for a slice should never require a search.
Key Decisions
One Project or Multiple?
Single project - the default for VSA. Keep it simple:
MyApp.Api/
Features/
Domain/
Data/
Shared/
Multiple projects - only when you need strict compile-time enforcement:
MyApp.Api/ ← entry point
MyApp.Features/ ← all features
MyApp.Domain/ ← domain entities
MyApp.Data/ ← EF Core, migrations
Start with one project. Split when you have a reason. Folder boundaries are cheap to change; project boundaries are not. If you want boundary enforcement without extra projects, architecture tests on namespaces get you most of the way.
Where Do Domain Entities Live?
In a Domain/ folder within the same project:
Domain/
Order.cs
LineItem.cs
Customer.cs
Product.cs
Common/
Entity.cs
AggregateRoot.cs
IDomainEvent.cs
Domain entities are shared across features. An Order entity is used by PlaceOrder, GetOrder, and CancelOrder. Slices own their request and response types; they share the domain model underneath.
Where Does the DbContext Live?
In a Data/ folder:
Data/
ApplicationDbContext.cs
Configurations/
OrderConfiguration.cs
CustomerConfiguration.cs
Migrations/
EF Core configurations are separate from features - they're infrastructure, not business logic.
Shared Code (Cross-Cutting Concerns)
Pipeline behaviors, middleware, and shared abstractions in Shared/:
Shared/
Behaviors/
ValidationBehavior.cs
LoggingBehavior.cs
CachingBehavior.cs
Middleware/
ExceptionHandlingMiddleware.cs
RequestLoggingMiddleware.cs
Abstractions/
ICommand.cs
IQuery.cs
ICacheable.cs
Extensions/
ResultExtensions.cs
Keep this folder small and boring. If Shared starts accumulating business logic, a slice boundary is leaking; see cross-cutting concerns in Vertical Slice Architecture for what belongs here and what doesn't.
When Features Get Complex
A simple feature fits in one file. A complex feature graduates to a folder:
Features/
Orders/
PlaceOrder/
PlaceOrderCommand.cs
PlaceOrderHandler.cs
PlaceOrderValidator.cs
PlaceOrderResponse.cs
GetOrder/
GetOrderQuery.cs
GetOrderHandler.cs
Shared/
OrderResponse.cs
OrdersModule.cs
My threshold: split into a folder when the single file grows past roughly 150-200 lines, or when a slice needs private helper classes that would pollute the file.
A feature-local Shared/ folder (like Orders/Shared/) is fine for DTOs reused by two or three sibling slices, like the OrderResponse that both GetOrder and GetOrders return. It's still inside the feature boundary, which is very different from a global shared folder.
Scaling to 50+ Features
A flat Features folder stops working around a few dozen slices. The fix is one more level: group by domain area.
Features/
Ordering/
PlaceOrder.cs
GetOrder.cs
CancelOrder.cs
OrderingModule.cs
Catalog/
CreateProduct.cs
SearchProducts.cs
CatalogModule.cs
Identity/
RegisterUser.cs
Login.cs
RefreshToken.cs
IdentityModule.cs
Shipping/
CreateShipment.cs
TrackShipment.cs
ShippingModule.cs
These groups aren't arbitrary. They mirror bounded contexts, and each one is a candidate module if you later evolve toward a modular monolith. At that point each domain area gets its own project (or set of projects), and the folder structure you already have becomes the module structure. I've written about exactly where vertical slices fit inside a modular monolith.
The practical signals that you've hit this stage:
- You scroll to find anything in
Features/ - Two domain areas keep reaching into each other's entities
- Different teams own different feature groups and step on each other in PRs
Restructuring is mechanical: create the domain-area folders, move files, fix namespaces. Do it in one PR before the pain compounds.
Conventions That Keep the Structure Healthy
A folder structure only stays clean if a few conventions back it up:
- Namespace mirrors folder.
MyApp.Api.Features.Ordering.PlaceOrdertells you exactly where the file lives. Most IDEs enforce this automatically. - Handlers are
internal. Nothing outside the slice should call a handler directly. The endpoint (or dispatcher) is the only entry point. - One route prefix per module.
OrdersModuleowns/api/orders; no other module maps routes under it. - No slice-to-slice references. If
PlaceOrderneeds something fromShipping, that's a domain service or a domain event, not ausingstatement. A couple of architecture tests will hold this line for you.
Summary
A practical VSA folder structure:
- Features folder - one file per use case, named as a verb
- Domain folder - shared entities and value objects
- Data folder - DbContext, configurations, migrations
- Shared folder - pipeline behaviors, middleware, abstractions (keep it boring)
- Single project to start, split only when you need compile-time boundaries
- Single-file slices first, folders past ~150-200 lines
- Domain-area grouping at 50+ features, mirroring bounded contexts
The structure should make it obvious what your application does by reading the feature folder names.
Thanks for reading, and stay awesome!
Frequently Asked Questions
How do you structure a Vertical Slice Architecture project?
Organize a Features folder with one file or subfolder per use case, grouped by domain area. Keep shared domain entities in a Domain folder, EF Core infrastructure in Data, and cross-cutting behaviors in Shared. One project is enough to start.
Should Vertical Slice Architecture use one project or multiple?
Start with a single project. Multiple projects only add value when you need compile-time enforcement of boundaries, which usually matters once teams and feature counts grow or when you evolve toward a modular monolith.
Where do domain entities live in Vertical Slice Architecture?
In a shared Domain folder, because entities like Order are used by several slices (PlaceOrder, GetOrder, CancelOrder). Slices own their request, handler, and response; they share the domain model underneath.
How do you keep a Features folder manageable with 50+ features?
Introduce a domain-area level: Features/Ordering, Features/Catalog, Features/Identity, each containing its use cases and endpoint module. The groups mirror bounded contexts and give you a natural path to a modular monolith.



