Feature-Sliced Design (FSD) Documentation

repository·main·Indexed 25 days ago

https://github.com/feature-sliced/documentation

Documentation for Feature-Sliced Design (FSD), a stack-agnostic architectural methodology for scaffolding frontend applications. FSD provides rules and conventions for organizing code into layers, slices, and segments to improve project structure, scalability, and onboarding. It focuses on business orientation and strict dependency rules to ensure stability during refactoring and reduce technical debt in large-scale projects.

Tokens
79K
Snippets
162
Records
300
Agent score
75%

What's inside Feature-Sliced Design

  1. What is Feature-Sliced Design (FSD)?

    main

    Feature-Sliced Design (FSD) is an architectural methodology for scaffolding front-end applications. It is a compilation of rules and conventions for organizing code to make projects more understandable and structured, especially when facing changing business requirements.

    Key characteristics:

    • Stack Agnostic: Can be used for web or native applications.
    • Organization: Code is organized by scope of influence (layers), by domain (slices), and by technical purpose (segments).
    • Dependency Rules: A module on a particular layer cannot use other modules on the same layer, or the layers above it, ensuring stability during refactoring.
    • Business Orientation: Projects are split into business domains, allowing developers to navigate code based on project features.
  2. Understand the mission and goals of Feature-Sliced Design

    main

    Feature-Sliced Design (FSD) aims to balance ideological perfection with practical simplicity. The methodology is designed to be intuitive and accessible to a wide range of developers, not just senior leaders.

    Key goals include:

    • Intuitive and Clear: Ensuring most team members can easily understand and apply the methodology.
    • Solving Everyday Problems: Providing clear standards and solutions for common development challenges. This is supported by tools like CLI and linters to reduce repetitive architectural issues and promote verified approaches.
  3. Understand the goals and limitations of Feature-Sliced Design

    main

    Feature-Sliced Design (FSD) is an architectural methodology designed to balance ideology with simplicity. Its primary goals are:

    • Intuitive clarity: The methodology is intended to be accessible to a wide range of developers within a team, not just seniors or leads.
    • Solving everyday problems: It provides battle-tested solutions to common architectural and development problems. To support this, the methodology is accompanied by tools like CLIs and linters to help developers implement the approach easily.

    Limitations to keep in mind:

    • Not a silver bullet: It is not a universal solution that fits every single project perfectly.
    • Complexity curve: FSD is not intended for extremely simple or trivial projects where the overhead might not be justified. Some architectural concepts require experience with real-world problems to be fully understood intuitively.
    • Core values: The methodology prioritizes simplicity and extensibility.
  4. What is a Slice group and how does it work

    main

    A Slice group is a way to organize related slices within the same layer by placing them closer together to make the structure easier to navigate.

    **Key characteristics:

    • Not a slice: A Slice group is purely a structural organization tool. It does not have segments (like model, ui, api) or a public API (index.ts).
    • No shared code: You should not put common code used by multiple slices inside a Slice group folder; that code belongs in the slices themselves or other appropriate locations.
    • No impact on rules: Even when grouped, each slice remains independent. The isolation between slices and the dependency rules of Feature-Sliced Design (FSD) remain unchanged.
    • Optional: Slice groups are not mandatory. They should only be introduced when a flat structure becomes difficult to navigate due to a high number of slices.
  5. What is a Public API in Feature-Sliced Design

    main

    A Public API is the official entry point for a Slice, acting as a Contract and a Gate between the Slice and external code. External code must access Slice internals exclusively through this path. Typically, a Public API is implemented as an index file that re-exports specific objects from the Slice.

    Goals of a good Public API:

    1. No impact from internal structure changes: Changing folders inside a Slice should not break external code.
    2. Major behavior changes = API changes: If a Slice's core logic changes significantly, the Public API should reflect that.
    3. Expose only what is necessary: Do not expose the entire implementation; select only the features required by external consumers.
    export { LoginPage } from "./ui/LoginPage";
    export { RegisterPage } from "./ui/RegisterPage";
  6. What is Desegmentation and why to avoid it

    main

    Desegmentation is a code organization pattern where files are grouped by their technical role (e.g., components, utils, stores, actions) rather than by their business domain. While this pattern is common in frameworks like Next.js or Nuxt due to ease of use with auto-imports and file-based routing, it leads to several issues as a project scales:

    • Low Cohesion: Modifying a single feature requires jumping between multiple folders like pages, components, and stores.
    • High Coupling: It becomes easy to create unintended dependencies between components, leading to complex dependency webs.
    • Difficult Refactoring: Separating code related to a specific domain becomes a manual, error-prone task of hunting down scattered files.

    In Feature-Sliced Design (FSD), desegmentation often manifests as folders named after technical roles within slices (e.g., features/delivery/ui/components) or generic filenames like types.ts and utils.ts that mix multiple business logics.

  7. Use the @x-notation for cross-imports in the Entities layer

    main

    When two entities on the same layer need to reference each other (cross-imports), use the @x-notation to create a specialized public API. This allows Entity B to import specifically from a subset of Entity A designed for cross-layer compatibility.

    Structure:

    • entities/A/@x/B.ts: A special public API in Entity A specifically for Entity B.
    • entities/A/index.ts: The regular public API for the rest of the app.

    Usage: Inside entities/B/, import from the @x path:

    import type { EntityA } from "entities/A/@x/B";

    Note: Only use this notation on the Entities layer. Keep cross-imports to a minimum.

  8. Requirements for Feature-Sliced Design methodology

    main

    For the Feature-Sliced Design methodology to be effective in a project, it must satisfy two primary requirements:

    1. Provide clear methods for composing Features, Processes, and Entities: This includes defining specific criteria for code splitting and naming conventions.
    2. Provide an architecture that is flexible to changing requirements: The structure must allow for easy adaptation as business needs and user requirements evolve.
  9. Use Entities and Processes in v2

    main

    v2 introduces two new layers to manage complexity and coupling:

    • /entities: Contains slices related directly to business models or synthetic frontend entities (e.g., user, i18n, order, blog).
    • /processes: Contains business processes that penetrate multiple parts of the app. This layer is optional and should be used when logic begins to blur across several pages (e.g., payment, auth, quick-tour).
  10. Manage localization and i18n content

    main

    Localization is handled by Starlight's built-in locale support. Content for specific locales is stored in src/content/<locale>/docs/.

    Supported locales include:

    • English (root)
    • Russian
    • Uzbek
    • Korean
    • Japanese
    • Vietnamese
    • Chinese
  11. Handle business entity cross-references

    main

    Business entities (e.g., Song, Album) often reference each other. Because FSD restricts cross-imports between slices (a slice can only import from layers strictly below it), use one of these two patterns to manage connections:

    1. Parametrize your types

    Make types accept generic arguments to act as slots for other entities. This works well for loosely coupled entities.

    interface Song<ArtistType extends { id: string }> {
      id: number;
      title: string;
      artists: Array<ArtistType>;
    }

    2. Use the @x notation for explicit cross-imports

    When entities are tightly coupled, create a special public API within the source slice using the @x notation. This allows other slices to import specific types without violating architectural boundaries.

    Structure:

    • entities/song/@x/artist.ts (The public API for the artist entity to import from)
    • entities/song/index.ts (The regular public API)

    Example Implementation:

    In entities/song/@x/artist.ts:

    export type { Song } from "../model/song.ts";

    In entities/artist/model/artist.ts:

    import type { Song } from "entities/song/@x/artist";
    
    export interface Artist {
      name: string;
      songs: Array<Song>;
    }
  12. How the Page-First approach works in v2.1

    main

    In v2.1, the architectural mental model shifts from an Entity/Feature-centric approach to a Pages-First approach.

    v2.0 vs v2.1 Mental Models

    • v2.0 (Entity/Feature-centric): Applications were decomposed into small units (Entities and Features), which were then combined into Widgets and finally Pages. This often led to business logic being overly concentrated in the entity/feature layers, leaving Pages as mere composition layers with weak responsibilities.
    • v2.1 (Pages-First): The Page is treated as the primary unit of responsibility. Developers navigate the codebase starting from the Page.

    Core Principles of v2.1

    • Page Responsibility: Place major UI and business logic directly inside the Page.
    • Shared Layer: Keep only purely reusable elements in the shared layer.
    • Selective Extraction: Only move logic into feature or entity layers if it is actually shared across multiple Pages.

    Benefits

    1. Clearer Responsibility: Pages become distinct units of logic and UI.
    2. Leaner Shared Layer: Prevents the shared layer from becoming bloated, simplifying dependencies.
    3. Reduced Over-abstraction: Logic is only abstracted when actual reuse is required.