Skip to main content
SEMastery
Architecturebeginner

Screaming Architecture in .NET: Let Your Folders Tell the Story

Learn Screaming Architecture in .NET in plain words. Make your folder structure shout the business purpose, not the framework, with diagrams and real examples.

11 min readUpdated December 31, 2025

A library that looks like a library

Imagine you walk into a building you have never visited. You see a big entrance, a counter where people check books in and out, quiet reading rooms, and long shelves full of books. You do not need a sign. You instantly know: this is a library.

Now imagine a different building. You see a kitchen near the front, a dining area, bedrooms upstairs, and a small garden. Again, no sign needed. You know: this is a house.

The building's design screams its purpose. You understand what it is for just by looking at the rooms and how they are arranged.

Robert C. Martin, the engineer many people call "Uncle Bob", asked a simple question about software. When someone opens your project and looks at the top folders, do they instantly know what the app does? Or do they only learn which tools it uses?

That idea is called Screaming Architecture. Your folder structure should scream the business purpose of the app — like a kirana shop's shelves scream "groceries" — not just scream the name of the framework.

What "screaming" really means

Most .NET projects look like this when you open them:

src/
  Controllers/
  Services/
  Repositories/
  Models/
  DTOs/
  Validators/

Look at those folders. What does this app do? Is it a banking app? A food delivery app? A hospital system? You have no idea. These folder names only tell you how the code is built — using controllers, services, and repositories. That is the language of ASP.NET Core, not the language of the business.

This is what Uncle Bob warned about. He said the top-level structure of these apps screams "ASP.NET" or "Spring" or "Rails". It does not scream what the system is for.

A Screaming Architecture version of the same app looks like this:

src/
  Bookings/
  Payments/
  Apartments/
  Disputes/
  Reviews/

Now you can tell at a glance: this is an apartment booking system. The folders speak the language of the business. That is the whole point.

Figure 1: Two ways to read the same project. Technical folders hide the purpose; business folders reveal it.

Frameworks are tools, not the boss

Uncle Bob had a second, deeper point. He said:

Architectures are not about frameworks. Frameworks are tools to be used, not architectures to be conformed to.

Think about a carpenter. A hammer is a great tool. But a carpenter does not build a house around the hammer. The hammer serves the house. The house does not serve the hammer.

In the same way, ASP.NET Core, Entity Framework, and your web server are tools. They should serve your business rules. Your business rules should not be twisted to fit them. When your top folders are named after the business, you are putting the business first and the framework second. That is exactly the order Uncle Bob wanted.

This matters in real life. Frameworks change. One day you may swap a web framework, or move from one database library to another. If your whole project is organised around the framework, that change touches everything. If it is organised around the business, the framework is just a detail tucked inside each feature.

Who serves whom?

Business need
Use case
Framework as tool
Database as detail

Steps

1

Business need

Book an apartment

2

Use case

CreateBooking logic

3

Framework as tool

ASP.NET serves it

4

Database as detail

EF Core stores it

In Screaming Architecture, the business leads and tools follow.

Technical folders vs feature folders

Let us compare the two styles side by side. This is the heart of Screaming Architecture.

Technical folders (low clarity)Feature folders (screaming)
Controllers/Bookings/
Services/Payments/
Repositories/Apartments/
Models/Disputes/
Grouped by roleGrouped by purpose
Code for one feature spread outCode for one feature together

With technical folders, the code for a single feature — say "create a booking" — is spread across many folders. The controller is in one place, the service in another, the repository in a third. To change one feature, you jump between four or five folders.

With feature folders, everything a feature needs sits in one place. To change "Bookings", you open the Bookings folder and almost everything is right there. This is called high cohesion (things that change together live together) and low coupling (unrelated features do not get tangled).

Figure 2: Technical grouping scatters one feature; feature grouping keeps it together.

A real .NET example

Let us build a small slice of an apartment booking system. We want the project to scream "booking system". Here is how the folders look:

src/
  Bookings/
    CreateBooking.cs
    CancelBooking.cs
    GetBookingById.cs
    Booking.cs
  Payments/
    ChargePayment.cs
    RefundPayment.cs
  Apartments/
    ListApartments.cs
    Apartment.cs

Now look at the code for one feature. Notice how the endpoint, the logic, and the model all sit inside the Bookings folder. You do not hunt across the project.

namespace BookingApp.Bookings;
 
// The business entity — lives next to its use cases.
public class Booking
{
    public Guid Id { get; init; }
    public Guid ApartmentId { get; init; }
    public DateOnly CheckIn { get; init; }
    public DateOnly CheckOut { get; init; }
    public decimal TotalPrice { get; private set; }
 
    public void SetPrice(decimal pricePerNight)
    {
        var nights = CheckOut.DayNumber - CheckIn.DayNumber;
        TotalPrice = nights * pricePerNight;
    }
}

Here is the use case that creates a booking. It is a plain class — no special library needed. The whole job of "create a booking" is described in one file.

namespace BookingApp.Bookings;
 
public sealed class CreateBooking
{
    public record Request(Guid ApartmentId, DateOnly CheckIn, DateOnly CheckOut);
    public record Result(Guid BookingId, decimal TotalPrice);
 
    private readonly AppDbContext _db;
 
    public CreateBooking(AppDbContext db) => _db = db;
 
    public async Task<Result> HandleAsync(Request request)
    {
        var apartment = await _db.Apartments.FindAsync(request.ApartmentId)
            ?? throw new InvalidOperationException("Apartment not found.");
 
        var booking = new Booking
        {
            Id = Guid.NewGuid(),
            ApartmentId = request.ApartmentId,
            CheckIn = request.CheckIn,
            CheckOut = request.CheckOut
        };
        booking.SetPrice(apartment.PricePerNight);
 
        _db.Bookings.Add(booking);
        await _db.SaveChangesAsync();
 
        return new Result(booking.Id, booking.TotalPrice);
    }
}

And here is the endpoint that calls it. With minimal APIs in modern .NET, the endpoint can also live inside the Bookings folder. Notice the route placeholder is written inside backticks in the comment so it is treated as plain text: the GET route is GET /bookings/{id}.

namespace BookingApp.Bookings;
 
public static class BookingEndpoints
{
    public static void MapBookingEndpoints(this IEndpointRouteBuilder app)
    {
        app.MapPost("/bookings", async (
            CreateBooking.Request request,
            CreateBooking handler) =>
        {
            var result = await handler.HandleAsync(request);
            return Results.Created($"/bookings/{result.BookingId}", result);
        });
    }
}

Everything about bookings — the entity, the use case, the endpoint — sits together. The folder name and the files inside it scream "this app handles bookings". A new teammate finds their way around in minutes.

How a request flows in a screaming app

A request still travels through the usual steps. The difference is that all the code for those steps lives inside one feature folder, not scattered across the whole project.

Figure 3: A create-booking request, with every step living inside the Bookings folder.

Adding a new feature

Name the feature
Create the folder
Add use case + endpoint
Wire it up

Steps

1

Name the feature

e.g. Reviews

2

Create the folder

src/Reviews

3

Add use case + endpoint

All inside it

4

Wire it up

Map endpoints

With screaming folders you add one folder, not edits in five places.

Screaming Architecture and its cousins

People often mix up a few ideas. Let us clear them up gently.

Screaming Architecture is a principle. It says: name and group your folders so the purpose is obvious. It does not tell you exactly how to write each class.

Vertical Slice Architecture (VSA) is a pattern that puts all the code for one feature in one slice. A VSA project naturally screams its purpose, because the top folders are features. So VSA is one popular way to achieve Screaming Architecture.

Clean Architecture is about dependency direction — keeping your core business rules free from frameworks and databases. Screaming Architecture is about naming and grouping. They are not rivals. You can group by feature (screaming) and still keep clean dependency rules inside each feature.

IdeaWhat it controlsQuestion it answers
Screaming ArchitectureNaming and grouping"What does this app do?"
Vertical SliceWhere feature code lives"Where is the booking code?"
Clean ArchitectureDirection of dependencies"Can I swap the database safely?"

A small note on tools. For years many tutorials reached for the MediatR library to wire up slices, and MassTransit for messaging. Both are now commercially licensed for larger use. The good news is that Screaming Architecture does not need them at all. As you saw above, plain handler classes and minimal API endpoints do the job. The pattern is about organising code, not about any one library.

When it helps, and when to keep it simple

Screaming Architecture shines when an app has many clear features that grow over time — booking, payments, reviews, disputes, and so on. Each feature stays tidy in its own folder, and teams can work on different folders without bumping into each other.

For a tiny app with one or two endpoints, you do not need elaborate folders. A flat structure is fine. The principle still applies in spirit: even with two folders, name them after the business, not the framework. Start simple, and let the structure grow as the app grows.

There is also a sensible middle ground. Inside a feature folder you may still create small sub-folders when a feature gets big — for example, a Bookings/Internal area for helpers only that feature uses. That is fine. The key rule stays the same: the top level speaks the language of the business.

Figure 4: Choosing your structure based on app size and feature count.

Common mistakes to avoid

A few traps catch beginners. Watch out for these.

  • Half-screaming. You make feature folders like Bookings, but then add a giant shared Services folder where the real logic hides. Now the folder name lies. Keep the logic inside the feature.
  • Naming by data table, not by use case. A folder called Booking that only holds one entity class is weak. A folder called Bookings that holds the use cases — create, cancel, view — is strong. Name by what users do.
  • Forcing it on a tiny app. Five folders for a two-endpoint app is noise. Match the structure to the size.
  • Mixing two unrelated features. If Payments and Reviews start sharing classes, the boundary is breaking. Keep unrelated features apart so they can change on their own.

Quick recap

  • Screaming Architecture means your folder structure should shout what the app does, not which framework it uses.
  • It comes from Robert C. Martin (Uncle Bob), using the "a building looks like what it is for" analogy.
  • Technical folders like Controllers and Services hide the purpose. Feature folders like Bookings and Payments reveal it.
  • Frameworks are tools that serve the business, not the other way around.
  • It gives you high cohesion (one feature in one place) and low coupling (features stay independent).
  • It pairs naturally with Vertical Slice Architecture and can live alongside Clean Architecture.
  • You do not need MediatR or MassTransit (both now commercially licensed) — plain classes and minimal APIs work fine.
  • Start small, name folders after the business, and let the structure grow with the app.

References and further reading

Related Posts

Vertical Slice Architecture in .NET: The Easy Guide

Learn Vertical Slice Architecture in .NET in simple words. Organise code by feature instead of by layer, with diagrams, real examples, a comparison with Clean Architecture, and when to use each.

Read more

Clean Architecture Folder Structure in .NET: A Simple Guide

Learn how to organise a .NET solution with Clean Architecture. Understand the Domain, Application, Infrastructure, and Presentation layers, the dependency rule, and the exact folders, with diagrams and examples.

Read more

What Is a Modular Monolith? A Beginner-Friendly Guide for .NET

Understand the modular monolith in simple words: one app, strong internal walls. Learn how it compares to monoliths and microservices, why it is the 2026 default for most .NET teams, and how to build one.

Read more

N-Layered vs Clean vs Vertical Slice Architecture in .NET

A simple, friendly guide comparing N-layered, Clean, and Vertical Slice architecture in .NET, with diagrams, code, tables, and clear advice on when to pick each one.

Read more

Clean Architecture: The Missing Chapter Most Tutorials Skip

The missing chapter of Clean Architecture in .NET: where code really goes, what the dependency rule means, and the pragmatic choices tutorials skip.

Read more

The Best Way to Structure .NET Projects: Clean Architecture + Vertical Slices

A friendly guide to structuring .NET projects by mixing Clean Architecture with Vertical Slices, with diagrams, code, tables, and simple, beginner-ready advice.

Read more