What I learned studying Feature-Sliced Design and why I decided to migrate to Vertical Slice ArchitectureSaturday, May 16, 2026 at 4:23 AM6 min read

What I learned studying Feature-Sliced Design and why I decided to migrate to Vertical Slice Architecture

img-developer.jpg

In recent months, I have been studying modern frontend architectures more deeply and trying to understand which decisions actually make sense in the context of React/Next.js applications that start small but grow over time.

During this process, I ended up diving into some content about Feature-Sliced Design (FSD), an architecture that has gained a lot of popularity in recent years in the frontend ecosystem. The proposal is interesting: to create a more scalable structure, with clear boundaries, explicit import rules, and a more organized separation of responsibilities.

In theory, this sounds great, but while studying the subject and analyzing the current structure of a personal project I'm working on, I began to realize that perhaps FSD wasn't exactly what I needed at this moment.

Instead, I decided to start a gradual migration from the current Layered Architecture to Vertical Slice Architecture (VSA).

And honestly? The further I advance in this migration, the more sense it makes for the project.

The current project architecture

The project I'm working on was born using a more traditional layered structure:

├─ components/
├─ hooks/
├─ services/
├─ types/
└─ utils/

This worked very well for a while. The project was small, the features were relatively simple, and code navigation was smooth.

As new functionalities were added, I started to notice some classic signs:

  • logic of a feature spread across multiple directories
  • increased mental context needed to change something simple
  • greater difficulty in finding everything related to a feature
  • hooks, services, and types becoming decoupled from the domain
  • gradual growth of the shared/utils folder

Nothing too chaotic yet, but enough to realize that the current structure was starting to lose some cohesion.

Why I identified with Feature-Sliced Design

The first positive point of FSD is that it was specifically designed for the frontend. This already differentiates it significantly from architectures like Clean Architecture or Hexagonal Architecture, which usually come from the backend world and end up being adapted for the frontend later.

Another strong point is the documentation and the clarity of the rules.

The FSD structure usually follows something like this:

├─ app/
├─ pages/
├─ widgets/
├─ features/
├─ entities/
└─ shared/

And within these layers, there are slices and segments:

├─ features/
│  └─ auth/
│     ├─ api/
│     ├─ lib/
│     ├─ model/
│     └─ ui/

The proposal here is very good because it:

  • avoids circular dependencies
  • makes boundaries explicit
  • improves scalability
  • facilitates work among multiple developers
  • encapsulates features

In addition, I really liked the idea of a Public API per slice. Something like: features/auth/index.ts serving as a single export point.

I will probably leverage this concept in my project even without using full FSD.

Where I started to have doubts

While studying FSD, I began to compare the theory with the real problems I was trying to solve in my project. And then some things started to bother me.

Feature cohesion

One of the most interesting criticisms I found about FSD is that, although it organizes individual slices well, the feature often remains spread across different layers.

For example:

  • UI in widgets
  • logic in features
  • state in entities
  • API in shared

In practice, to change a simple feature, you still end up navigating through several different directories. And that's exactly what I started to feel in my project's current model. I wanted to bring closer the parts that change together.

Mental model closer to the business

Another concept I found interesting was that of "Screaming Architecture". The idea is simple:

the project structure should show the system's domain and not the architectural pattern used.

That is, opening the project and seeing something like this:

├─ features/
│  ├─ auth/
│  ├─ spots/
│  ├─ stories/
│  └─ user/

makes much more sense to me today than:

├─ components/
├─ services/
├─ hooks/

or even:

├─ entities/
├─ widgets/
├─ features/

At the end of the day, what I want to find quickly is the domain related to the problem I'm solving.

Why not adopt FSD now

I don't think FSD is bad. In fact, I think it solves real problems, especially in very large applications, with multiple teams and strict boundary rules.

But in the current context of my project, I started to feel that it would add a considerable amount of structural complexity too early.

Mainly for a few reasons:

  • many architectural categories
  • higher learning curve
  • excessive ceremony for the current project size
  • more decisions about "where something should go"
  • greater difficulty of incremental adoption

Today my project is still evolving, meaning features change, structures change, and domains change.

And I wanted an architecture that would allow me to grow without having to anticipate so many rules right from the start.

The decision for Vertical Slice Architecture

After analyzing the trade-offs, the approach that made the most sense was to gradually migrate to Vertical Slice Architecture. The idea is relatively simple:

Each feature now owns its:

  • components
  • hooks
  • services
  • types
  • utils

Everything is grouped by domain. Something close to this:

├─ features/
│  ├─ spots/
│  │  ├─ components/
│  │  ├─ hooks/
│  │  ├─ services/
│  │  └─ types.ts
│  └─ stories/
│     ├─ components/
│     ├─ hooks/
│     └─ services/

And only what is truly shared among multiple features moves up to:

├─ shared/

What I'm migrating in my project

I recently started structuring a more complete migration plan for the project. Some decisions I made:

  • Header, Sidebar, and truly global components go to shared/ui
  • specific hooks cease to exist in /hooks and move inside the feature
  • services cease to be global
  • types stay close to the domain
  • feature-specific utils are no longer scattered in /utils

For example:

Before:

├─ hooks/
│  └─ useSpot.ts
├─ services/
│  └─ getSpot.ts
├─ types/
│  └─ spots.ts

After:

├─ features/
│  ├─ spots/
│  │  ├─ hooks/
│  │  │  └─ useSpot.ts
│  │  ├─ services/
│  │  │  └─ getSpot.ts
│  │  └─ types.ts

It may seem like a small change superficially, but in practice, this completely changes the development and maintenance experience as the project grows.

The main gain so far

The biggest gain I noticed wasn't organization, it was context. Opening a folder and finding almost everything related to a feature greatly reduces the mental cost of working on the project.

In addition:

  • onboarding tends to be simpler
  • refactors become safer
  • discoverability greatly improves
  • feature ownership becomes clearer

But not everything is rosy

It's obvious that Vertical Slice also has its trade-offs. Some points I still need to be careful about during the migration are:

  • avoid coupling between features
  • don't turn shared/ into a generic folder
  • avoid abstractions too early
  • don't fall into unnecessary duplication

Today I'm adopting a simple rule:

if something is used by only one feature, it belongs to that feature.

It only moves to shared/ when it truly makes sense.

Conclusion

Studying Feature-Sliced Design was extremely useful because it helped me see architectural problems that I was already starting to feel in my project. Even without adopting FSD at this moment, several concepts remain valuable:

  • explicit boundaries
  • encapsulation
  • public APIs
  • domain-oriented organization

But today, for the current stage of the project, Vertical Slice Architecture seems to deliver a better balance between:

  • scalability
  • simplicity
  • cohesion
  • flexibility

And perhaps the most important point is: the structure begins to reflect the application's business more than the technology used.