January 18, 20265 min read

Feature-Sliced Design: Why I Stopped Fighting Vue's Folder Structure

Vue.jsNuxt.jsArchitecture

After wrestling with feature folders, domain folders, and flat structures — FSD finally gave me a mental model that scales.

The problem with flat structure

Early-stage projects start flat: components/, pages/, store/. It works until you hit ~20 features. Then you're searching for UserCard in a directory with 80 components.

What FSD actually is

FSD organises code into layers (app → pages → widgets → features → entities → shared), each containing slices (business domains), each slice containing segments (ui, model, api). The strict rule: a layer can only import from layers below it.

src/
  app/         # providers, router, global styles
  pages/       # route-level compositions
  widgets/     # self-contained UI blocks
  features/    # user actions (auth, cart, search)
  entities/    # business models (user, product)
  shared/      # ui kit, helpers, types

Applying it in Nuxt.js

Nuxt's pages/ maps to FSD's pages layer naturally. I keep Nuxt's auto-imports for shared/ui and configure path aliases so @entities/user resolves correctly. Pinia stores live in the model segment of their slice.

The one rule that matters

The import direction rule is what makes FSD work. Enforce it with eslint-plugin-boundaries. Without the linter, teams slowly break it and you lose the benefit.

When not to use it

FSD adds upfront structure overhead. For a landing page or a <5 screen app, it's overkill. The break-even point is roughly when you have 3+ developers or 10+ distinct user flows.