You're slicing your architecture wrong!
Basti Ortiz

Basti Ortiz @somedood

About: Web developer. Open-source contributor. Learner. Writer. Mentor. Leader.

Location:
Philippines
Joined:
Oct 19, 2018

You're slicing your architecture wrong!

Publish Date: May 15
79 25

For the longest time, the "separation of concerns" has been the ultimate guiding principle of software engineering. We thus structure our codebases accordingly:

  • Grouping related files by responsibility;
  • Partitioning logic by technical layers;
  • And sometimes even isolating by programming language.1

Popular architectural patterns such as the Model-View-Controller (MVC) have applied and codified this principle to the point of dogma. Universities, bootcamps, and courses everywhere teach and perpetuate the notion that the MVC architecture is the be-all and end-all of architectural patterns.

To be fair, the MVC architecture is indeed often the correct mental model for fathoming any CRUD-heavy application (i.e., virtually 99.9% of web applications2) because it formalizes the flow of data from the source (i.e., the "model") to the interface (i.e., the "view") as well as the mutation and actuation on said data (i.e., the "controller"). It is quite literally the essence of CRUD.

But, is MVC also the correct framework for structuring codebases?

Does MVC supposedly3 being the correct mental model necessarily mean we should structure our directories as such?

In this article, we'll explore a better way to structure a codebase using a vertically sliced architecture instead of the classic models/, views/, and controllers/ layout.

Horizontally Sliced Architectures

The MVC architecture is an example of a horizontally sliced architecture. In a horizontally sliced architecture, the separation of concerns is sliced according to technical layers.

A diagram of a horizontally sliced three-layer architecture featuring the MVC architecture

Note that the layers needn't be exclusively "models", "views", and "controllers". In a full-stack web application, you might find yourself slicing by "components", "endpoints", and "databases" instead.

models/
├── feature-a.ts
├── feature-b.ts
└── feature-c.ts
controllers/
├── feature-a.ts
├── feature-b.ts
└── feature-c.ts
views/
├── feature-a.tsx
├── feature-b.tsx
└── feature-c.tsx
Enter fullscreen mode Exit fullscreen mode

So, what's wrong with this project structure?

  • To add a new feature, you must jump between multiple directories—namely models/feature/*, controllers/feature/*, and views/feature/*. Compounded over time, that's a lot of context-switching, mental overhead, and navigational ceremony!
  • It's often not immediately apparent which modules are used by a particular feature. As everything is horizontally sliced, each module can theoretically import any module from the layer below. This makes it difficult to track and assess the impact of code changes.
  • Consequently, modules across layers within the scope of a single feature tend to exhibit high coupling and low-to-medium cohesion.
  • "Uh... which files go where again?" – Probably you for the past 10 minutes, thinking about where to put new files for a feature.

Vertically Sliced Architectures

Now let's turn MVC on its side—literally! In a vertically sliced architecture, the separation of concerns is sliced according to features. The core idea being: each feature module must encapsulate only its own end-to-end logic and nothing else.

A diagram of a vertically sliced three-layer architecture where a feature module is superimposed on all layers of the tech stack

In practice, here is what a feature-driven project structure could look like:

features/
├── feature-a/
│   ├── model.ts
│   ├── controller.ts
│   └── view.tsx
├── feature-b/
│   ├── model.ts
│   ├── controller.ts
│   └── view.tsx
└── feature-c/
    ├── model.ts
    ├── controller.ts
    └── view.tsx
Enter fullscreen mode Exit fullscreen mode

Shared logic across multiple features (e.g., database models, common utilities, etc.) may of course be refactored into shared modules elsewhere. What's important is that the feature-specific logic is self-contained and end-to-end.

Interestingly, though, the MVC patterns have not totally disappeared even in a vertically sliced architecture—as evidenced by the internal model.ts, controller.ts, and view.tsx files within a particular feature module. The slicing is different, yet the MVC-style separation of concerns remains in spirit.

So, what makes this better?

  • All the code related to a particular feature can be found within a single directory. No more back-and-forth between distant directories!4
  • The collocation of end-to-end logic lessens the cognitive load when developing features or debugging behaviors.5
  • By construction, a feature-driven architecture naturally leads to highly independent feature modules that exhibit low coupling (between vertical slices) and high cohesion (within vertical slices).

Example: React + Next.js

Nowadays, most full-stack web frameworks provide routing as a first-class feature. In Next.js, the src/app/ directory contains the entry points for each route. Specifically, the page.tsx file exports the component that should be rendered onto the page for that particular route.

Now let's imagine the page.tsx file as an orchestrator that only imports feature modules from src/features/. A natural conclusion is that a vertically sliced project structure entails partitioning the application logic as self-contained "feature components" that can be imported by any route—or any entry point in general.

src/
├── app/
│   ├── dashboard/
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── page.tsx
├── features/
│   ├── create-order/
│   │   ├── index.tsx
│   │   ├── context.ts
│   │   ├── hooks.ts
│   │   └── actions.ts
│   └── login-form/
│       ├── index.tsx
│       ├── context.ts
│       ├── hooks.ts
│       └── actions.ts
├── database/
│   ├── index.ts
│   └── schema.ts
└── components/
    ├── card.tsx
    ├── button.tsx
    └── input.tsx
Enter fullscreen mode Exit fullscreen mode

Indeed, feature modules like create-order and login-form may contain feature-specific components, contexts, hooks, and server actions.

  • A feature-specific component may, for example, import from the shared src/components/ directory for common cards, buttons, and inputs.
  • Meanwhile, a feature-specific server action may invoke database queries from the shared src/database/ directory.

The key is to know when to extract shared logic (e.g., src/database/ and src/components/) and when to keep bespoke feature-specific logic isolated from the rest of the application.

Conclusion

At its core, the call to action is simple: simply turn MVC on its side.

Vertically sliced architectures set us up to write highly independent components that exhibit low coupling (between vertical slices) and high cohesion (within vertical slices). The result is a project structure that is considerably easier to read, understand, maintain, and extend.

Further Reading


  1. For example, in web development, it is quite common to have a dedicated css/ directory for stylesheets and a js/ directory for scripts. 

  2. Citation needed. 😅 

  3. For the sake of this article, we assume this to be generally true: that MVC is indeed the correct mental model for fathoming CRUD-heavy applications. 

  4. Admittedly, back-and-forth between sub-directories is nevertheless inevitable. However, the navigation is at least contained within a single core directory now instead of jumping between distant directories, which is a win in my book. 

  5. I can only back this up with my own personal experience as well as anecdotal evidence from my friends. 

Comments 25 total

  • Ava Nichols
    Ava NicholsMay 15, 2025

    Great post!

  • Michael Liang
    Michael LiangMay 15, 2025

    Nice post

  • DarkStarVue
    DarkStarVueMay 15, 2025

    This is awesome!

  • david duymelinck
    david duymelinckMay 15, 2025

    You call it features I see modules, but whatever the name it has the same goal, breaking the code down in more manageable pieces.

  • Nathan Tarbert
    Nathan TarbertMay 15, 2025

    love seeing thishonestly, searching all over for files always messes me up way more than it should. you ever wonder if most old habits in programming actually slow us down more than help?

  • Nevo David
    Nevo DavidMay 16, 2025

    pretty cool seeing folks push for more feature-driven setups - tbh i've always gotten lost digging through layers. you ever feel like habits from old patterns get in the way of trying new stuff?

  • Mike
    MikeMay 16, 2025

    Embracing a vertically sliced architecture turns sprawling MVC layers into self-contained feature modules, reducing context-switching and boosting maintainability.

  • Kevin Naidoo
    Kevin NaidooMay 16, 2025

    Nice! HMVC is a solid way to organise large projects. I use Django for this, it has a concept of "projects" and "apps" which makes it easier when the framework supports it.

  • Mike Talbot ⭐
    Mike Talbot ⭐May 16, 2025

    I've long been a proponent of this vertical slicing approach. When do you ever need to look at another feature's controller, view or model when working on a particular feature? The mental load is significantly greater, and onboarding new developers is much harder.

    Great article!

    • Daniel Hillmann
      Daniel HillmannMay 21, 2025

      And if you do, it may be a hint you are on a questionable track/path

  • Stas Sultanov
    Stas SultanovMay 16, 2025

    Yeh, it is funny to read articles like this.
    The truth is that there is no right answer, it is always about a tradeoff.

  • Adam Neves
    Adam NevesMay 16, 2025

    Sounds interesting, thanks for the article!

  • @ScottFred
    @ScottFredMay 16, 2025

    The Angular Team recently merged their Angular style Guide and now recommend a pattern similar to this where they recommend a feature based file organization. github.com/angular/angular/pull/60...

  • Angelo Mandato
    Angelo MandatoMay 17, 2025

    I also have maintained businesses with this concept of separate applications, or also referred to as modules, or better yet organizing independent applications that can work independently on their own. Amazon called this decoupled architecture. For business minded folks, avoiding the monolithic app at all levels is critical to being capable of easily pivoting as well as putting a cost on your assets/intellectual property.

  • Cody Pritchard
    Cody PritchardMay 17, 2025

    You're just describing FSD (feature sliced design)
    feature-sliced.github.io/documenta...

  • Avik Ghosh
    Avik GhoshMay 17, 2025

    This is such a clean articulation of a problem so many devs face but rarely address head-on. Vertical slicing aligns way better with how modern teams scale — especially when working across cross-functional domains, feature flags, or parallel delivery tracks.

    At [turtal-docs.in/], we're leaning heavily into vertically sliced systems to support our open-source contributor ecosystem. Each feature module owns its data flow, logic, and UI — reducing inter-slice dependencies and making code reviews and onboarding way easier.

    We're also ranking and rewarding contributors based on the quality and impact of their feature modules. If you're building or contributing to OSS with strong architectural discipline, we'd love to have you onboard and feature your work.

  • Nevo David
    Nevo DavidMay 18, 2025

    Yeah this nails the stuff I’ve struggled with in big projects. Keeping each feature in its own spot just keeps me sane.

  • sohail mughal
    sohail mughalMay 20, 2025

    Solid insights! Architecture decisions can make or break scalability. I recently looked into how apps like Truecaller mod apk manage their structure—super eye-opening. Clean architecture really does matter in the long run.

  • Caner
    CanerMay 20, 2025

    Nice article. Btw I think this is still MVC architecture . Folder structure does not impose an architecture . Vertical slice is done through messaging btw feature slices.( and if this is the way you done it , then sorry, haven't looked at the source code)

    • Basti Ortiz
      Basti OrtizMay 20, 2025

      Folder structure does not impose an architecture.

      That's true! The heart of what I was getting at in this article is the shift in perspective from the strictly horizontal layers of MVC to the more end-to-end vertical layers of feature-driven architectures.

      To your point: folder structures are indeed somewhat incidental to the chosen architecture, but it is admittedly heavily influenced by our mental framework of that architecture. This article seeks to reconsider that mental framework while keeping some spirit of MVC alive. An excerpt from the article:

      Interestingly, though, the MVC patterns have not totally disappeared even in a vertically sliced architecture—as evidenced by the internal model.ts, controller.ts, and view.tsx files within a particular feature module. The slicing is different, yet the MVC-style separation of concerns remains in spirit.


      Vertical slice is done through messaging btw feature slices

      I believe this is especially applicable to web applications (as in my examples), where the request-response cycle is quite literally messaging at its core. 😉

      Consider a POST request from a <form>. An end-to-end feature module spans the UI, the server endpoint, and the database operations. This is an entire vertical slice.

  • Tom
    TomMay 20, 2025

    Sounds like HMVC from the early 2000s to me

    • Basti Ortiz
      Basti OrtizMay 20, 2025

      It does look sorta like that, but that isn't really the spirit of the article. What I'm advocating for is an end-to-end vertical slicing of a codebase according to feature modules such that the data flow from the model to the presentation layer is a self-contained pipeline.

      I must reiterate: there is no explicit notion of a "controller" here—only data pipelines.

  • Phil Eberhardt
    Phil EberhardtMay 21, 2025

    I've been using this method myself for a bit and seemed to naturally happen when I moved from Backbone and Marionette many years ago to React. I never really thought about it as vertical slicing though, nice article.

    • Basti Ortiz
      Basti OrtizMay 21, 2025

      That's something I've realized within myself and my own circle of colleagues, too! It's like we all somehow independently converged on this pattern of vertically slicing our features. Given the independent validation, I think that makes it even more appealing.

  • GP
    GPMay 21, 2025

    VMVC make life easier than complicated. Be smart and stash all assets like images, fonts, and icons on a CDN. Just use the full URL when you need it. It's super simple when you wanna swap things out without the hassle of redeploying everything.

    Oh, and one more thing - if you can make magic happen with Node.js and React/Angular/Vue, stick with those. No need to complicate life with Next.js.

Add comment