feature-sliced/skills

feature-sliced-design

Official Feature-Sliced Design (FSD) v2.1 skill for applying the methodology to frontend projects. Use when the task involves organizing project structure with FSD layers, deciding where code belongs, placing static assets (images, icons, fonts, PDFs), grouping closely related slices, defining public APIs and import boundaries, resolving cross-imports or evaluating the @x pattern, deciding whether to create or remove an entity, evaluating whether the entities layer is needed at all, deciding wh…

All-time #1035 Trending #2111 First seen Mar 9, 2026
8-week activity · all time api

Installation

$ npx skills add feature-sliced/skills --skill feature-sliced-design

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Security audits

Partner security reviews for this skill.

agent-trust-hub SAFE

Analyzed May 1, 2026

The skill provides comprehensive documentation and guidelines for implementing the Feature-Sliced Design (FSD) v2.1 methodology in frontend projects. It includes architectural rules, code examples, and configuration guides for popular frameworks like Next.js, Nuxt, and Vite.

snyk LOW

Analyzed May 1, 2026

No issues detected.

socket Score 0.9000 · 0 alerts

Analyzed May 1, 2026

  • license 1
  • maintenance 1
  • quality 0.9
  • supply chain 1
  • vulnerability 1

0 alerts

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 93
License MIT
Default branch master
Open issues 0
Status Active

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 22,274 B
  • docs SUMMARY.md 935 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 18,512 installs

SKILL.md

Feature-Sliced Design (FSD) v2.1

Source: fsd.how | Strictness can be adjusted based on
project scale and team context.

How to use this skill. For placement decisions, start with the decision tree in Section 2 and use the placement table in Section 3 as a quick reference. To check a structure for violations, use the rules in Section 4. To resolve same-layer cross-imports, use Section 7. For task-specific guidance, load only the relevant reference files from Section 10; do not preload the rest.

1. Core philosophy & layer overview

FSD v2.1 core principle: "Start simple, extract when needed."

The extraction rule

Place code in pages/ first. Duplication across pages is acceptable and does not by itself require extraction to a lower layer. Extract only when all three conditions hold:

  1. The same code is used in multiple places right now, not hypothetically.
  2. It has a reason to change that is independent of any one consumer.
  3. The boundary has a focused responsibility.

The six layers

Not all layers are required. Most projects can start with only shared/, pages/, and app/. Add features/ and entities/ only when they provide clear value. Do not create empty layer folders "just in case." The widgets/ layer is discouraged (see the callout below).

FSD uses 6 standardized layers, listed here from highest to lowest:

app/       → App initialization, providers, routing
pages/     → Route-level composition, owns its own logic
widgets/   → Reusable UI blocks (discouraged, see the callout below)
features/  → Reusable user interactions (see the extraction rule above)
entities/  → Reusable business domain models (see the extraction rule above)
shared/    → Infrastructure with no business logic (UI kit, utils, API client)

The official layer reference discourages using the Widgets layer, and this skill follows it. Widgets may seem useful for representing independent UI blocks. However, in real frontend code, UI blocks often include logic required for user flows, such as data fetching, state management, and event handling. In this case, the responsibilities of Features, which handle user flows, and Widgets, which handle UI blocks, can overlap, making the boundary between the two layers unclear.

Not creating a widget does not mean moving the block elsewhere untouched. A screen-specific composition stays in pages; a reused action and the UI to perform it go to features; context-free UI goes to shared; an app-wide layout goes to app.

Discouraged is not deprecated: an existing widgets layer stays valid. See references/layer-structure.md for that case and for layout placement.

The import rule

A module may only import from layers strictly below it. Cross-imports between slices on the same layer are forbidden, with one narrow exception in Section 7.

// Allowed
import { Button } from "@/shared/ui/Button"; // features → shared
import { useUser } from "@/entities/user"; // pages → entities

// Violation
import { loginUser } from "@/features/auth"; // entities → features
import { likePost } from "@/features/like-post"; // features → features

Note: The processes/ layer is deprecated in v2.1. For migration details, read references/migration-guide.md.

2. Decision framework

When writing new code, follow this tree:

Step 1: Where is this code used?

  • Used in only one page → keep it in that pages/ slice.
  • Used in 2+ pages but duplication is manageable → keeping separate copies

in each page is also valid.

  • An entity or feature with a single consumer → keep it there (Steiger

flags this as insignificant-slice).

Step 2: Is it reusable infrastructure with no business logic?

The official layer reference draws the line for Shared like this: no business logic, but business-themed is fine (a company logo, a page layout), and so is UI logic (autocomplete, a search bar). Exchanging data with the backend and CRUD boilerplate are not business logic either. Business logic is a rule the product enforces on its own data, such as applying a discount to an order. If the code fits none of the exclusions and still does not clearly enforce a product rule, the term does not decide; go back to Step 1 and place it by where it is used.

  • UI components → shared/ui/
  • Utility functions → shared/lib/
  • API client, route constants → shared/api/ or shared/config/
  • Auth tokens, session management → shared/auth/
  • CRUD once several slices call it → shared/api/ (a single caller keeps

it, see Step 1)

Step 3: Is it a complete user action that several consumers share, with a focused responsibility and a reason to change of its own?

  • Yes → features/
  • Uncertain, single use, or speculative reuse → keep in the page.

Step 4: Is it a business domain model that several consumers share, with a focused responsibility and a reason to change of its own?

  • Yes → entities/
  • Uncertain, single use, or speculative reuse → keep in the page.

Step 5: Is it app-wide configuration?

  • Global providers, router, theme → app/

Golden Rule: When in doubt, keep it in pages/. Extract only when the extraction rule holds.

3. Quick placement table

Scenario Single use Confirmed multi-use
User profile form pages/profile/ui/ProfileForm.tsx features/profile-form/
Product card pages/products/ui/ProductCard.tsx entities/product/ui/ if the entity owns it
API request (read or CRUD) pages/product-detail/api/fetch-product.ts shared/api/ (no domain rules)
Auth token/session shared/auth/ shared/auth/
Auth login form pages/login/ui/LoginForm.tsx features/auth/
Generic Card layout shared/ui/Card/
Modal manager shared/ui/modal-manager/
Modal content pages/[page]/ui/SomeModal.tsx
Date formatting util shared/lib/format-date.ts

"Confirmed multi-use" means the extraction rule holds, not that a second consumer appeared: two similar copies that keep drifting apart stay in their pages (references/growth-walkthrough.md, Snapshot 1). Entity UI carries the Section 6 caution even when the rule does hold.

4. Architectural rules (MUST)

These rules are the foundation of FSD. Violations weaken the architecture. If you must break a rule, ensure it is an intentional design decision and document the reason in code (a comment or ADR).

4-1. Import only from lower layers

app → pages → widgets → features → entities → shared. Upward imports are forbidden. So are cross-imports between slices on the same layer, except through the other slice's public API as a last resort (Section 7, Strategy D).

4-2. Public API: every slice exports through index.ts

External consumers may only import from a slice's index.ts. Direct imports of internal files are forbidden.

// Correct
import { LoginForm } from "@/features/auth";

// Violation: bypasses public API
import { LoginForm } from "@/features/auth/ui/LoginForm";

Shared layer: Shared has no slices. Define a separate public API per segment (shared/ui/index.ts, shared/api/index.ts, etc.) rather than one top-level shared/index.ts. This keeps imports from Shared organized by intent.

Where one index over a segment's unrelated modules hurts bundling, give each component, library, or controller folder its own index instead (shared/ui/Button/index.ts as @/shared/ui/Button, shared/api/post/ as @/shared/api/post). That folder is then the boundary; reaching past it (@/shared/ui/Button/Button.tsx) is still a violation. See references/layer-structure.md for the shape.

Environment-specific entry points: a slice normally exposes one index.ts, and ad-hoc variations are not recommended. If a single index cannot preserve a runtime boundary, add an entry point such as index.server.ts. See references/framework-integration.md.

4-3. No cross-imports between slices on the same layer

If two slices on the same layer need to share logic, follow the resolution order in Section 7. Never reach into another slice's internals.

4-4. Domain-based file naming (no desegmentation)

Name files after what they are for, the domain or concern they serve, not after their technical role. Technical-role names like types.ts, utils.ts, helpers.ts mix unrelated concerns in a single file and reduce cohesion.

// BAD: technical-role naming
model/types.ts          ← Which types? User? Order? Mixed?
model/utils.ts

// GOOD: domain-based naming
model/user.ts           ← User types + related logic
model/order.ts          ← Order types + related logic
api/fetch-profile.ts    ← Clear purpose

4-5. No business logic in shared/

Shared contains only infrastructure: UI kit, utilities, API client setup, route constants, assets. Business calculations, domain rules, and workflows belong in entities/ or higher layers. Section 2, Step 2 says what counts.

// BAD: business logic in shared
// shared/lib/userHelpers.ts
export const calculateUserReputation = (user) => { ... };

// GOOD: move it to whoever owns the rule
// pages/profile/model/reputation.ts       ← while the profile page owns it
// entities/user/model/reputation.ts       ← once a user boundary is earned
export const calculateUserReputation = (user) => { ... };

5. Recommendations (SHOULD)

5-1. Pages first: place code where it is used

Place code in pages/ first. Extract to lower layers only when truly needed. Extraction is a design decision that affects the whole project, so the threshold should be high.

What stays in pages:

  • Large UI blocks used only in one page
  • Page-specific forms, validation, data fetching, state management
  • Page-specific business logic and API integrations
  • Code that looks reusable but is simpler to keep local

Evolution pattern: Start with everything in pages/profile/. Extract the shared model to entities/user/ when a second page consumes it and the extraction rule holds. A response type that several pages read is not one of those cases: it stays in shared/api. Keep page-specific API calls and UI in the page.

5-2. Be conservative with entities

The entities layer is highly accessible (almost every other layer can import from it), so changes propagate widely.

  1. Start without entities. shared/ + pages/ + app/ is valid FSD.

Thin-client apps rarely need entities.

  1. Do not split slices prematurely. Keep code in pages. Extract to

entities only when the extraction rule holds.

  1. Business logic does not automatically require an entity. Keeping types

in shared/api and logic in the current slice's model/ segment may be sufficient.

  1. CRUD is infrastructure, not entities. Place it by the request

placement rule: with its consumer while there is one, in shared/api/ once several slices call it.

  1. Place auth data in shared/auth/ or shared/api/. Tokens and login

DTOs are auth-context-dependent and rarely reused outside authentication.

For detailed guidance on keeping the entities layer clean (when to skip it entirely, how to isolate business contexts, why CRUD belongs in shared/api), see references/excessive-entities.md.

5-3. Start with minimal layers

// Valid minimal FSD project
src/
  app/         ← Providers, routing
  pages/       ← All page-level code
  shared/      ← UI kit, utils, API client

// Add layers only when an actual use case requires them:
// + features/  ← User-action boundaries that need one shared home
// + entities/  ← Domain boundaries that need one shared home
// (widgets/ is discouraged; see Section 1 for where that code goes instead)

5-4. Validate with the Steiger linter

Steiger is the official FSD linter. Key rules:

  • insignificant-slice: Flags a slice with no references, or with one,

and suggests merging it into the layer above. Pages may hold a single reference, and so may slices used only from app/.

  • excessive-slicing: Suggests merging or grouping when a layer has too

many slices.

npm install -D @feature-sliced/steiger
npx steiger src

6. Anti-patterns (AVOID)

  • Do not create entities prematurely. Data structures used in only one

place belong in that place.

  • Do not put CRUD in entities. Plain CRUD is shared/api/. An

operation that carries business rules is placed by who owns the rule, which may be an entity, a feature, or the page running the workflow.

  • Do not create a user entity just for auth data. Tokens and login DTOs

belong in shared/auth/ or shared/api/.

  • Do not abuse @x. It is a necessary compromise, not a recommended

pattern. The notation is for the entities layer only, and only when boundary merge is genuinely impossible. Features and widgets handle cross-imports through strategies A through D (see Section 7).

  • Do not extract single-use code. A feature or entity used by only one

page should stay in that page.

  • Do not use technical-role file names. Use domain-based names

(see Rule 4-4).

  • Be cautious adding UI to entities. Entity UI tempts cross-imports from

other entities. If you add UI segments to entities, only import them from higher layers (features, pages, app), never from other entities.

  • Do not create god slices. Slices with excessively broad responsibilities

should be split into focused slices (e.g., split user-management/ into auth/, profile-edit/, password-reset/).

  • Do not create a top-level assets/ segment. Place static assets next

to the code that uses them; global stylesheets and fonts go to app/. See references/asset-handling.md.

7. Cross-import resolution

Cross-imports are a code smell, not an absolute prohibition. The right strategy depends on the layer and the situation.

Entities layer: prefer boundary merge, @x is last resort

Cross-imports in entities are usually caused by splitting entities too granularly. Before reaching for @x, consider whether the boundaries should be merged.

@x is a necessary compromise, not a recommended approach. Use it only when boundaries genuinely cannot be merged, and document why. Overuse locks entity boundaries together and increases refactoring cost.

Features and widgets: four strategies (A, B, C, D)

In features and widgets, choose based on context:

  • Strategy A: slice merge. Two slices always change together → merge.
  • Strategy B: push to entities. A shared domain responsibility → move

it to the entity that owns it, keep UI in the feature.

  • Strategy C: compose from upper layer (IoC). The parent (pages or app)

imports both slices and connects them via render props, slots, or DI.

  • Strategy D: Public API access. When reuse is genuinely unavoidable,

allow it only through the slice's index.ts. Never reach into model/, store/, or internal files.

The @x notation is for the entities layer only. Features and widgets use strategies A through D above.

Strictness depends on project context

Cross-imports are dependencies that are generally best avoided, but sometimes used intentionally. Strictness varies by project context:

  • Early-stage products with heavy experimentation: allowing some

cross-imports may be a pragmatic speed trade-off.

  • Long-lived or regulated systems (fintech, large-scale services):

stricter boundaries pay off in maintainability and stability.

If a cross-import is introduced, treat it as a deliberate choice and document the reasoning in code (a comment explaining why other strategies do not apply).

For detailed code examples of each strategy, read references/cross-import-patterns.md.

8. Segments & structure rules

Standard segments

Segments group code within a slice by technical purpose:

  • ui/: UI components, styles, display-related code
  • model/: Data models, state stores, business logic, validation
  • api/: Backend integration, request functions, API-specific types
  • lib/: Internal utility functions for this slice
  • config/: Configuration, feature flags

Layer structure rules

  • App and Shared: No slices, organized directly by segments. Segments

within these layers may import from each other.

  • Pages, Widgets, Features, Entities: Slices first, then segments inside

each slice.

  • Slice groups (optional): A group folder may contain related slices on

the same layer for navigation purposes only. The group has no segments and no public API. See references/layer-structure.md for details.

File naming within segments

Always use domain-based names that describe what the code is about:

model/user.ts            ← User types + logic + store
model/order.ts           ← Order types + logic + store
api/fetch-profile.ts     ← Profile fetching
api/update-settings.ts   ← Settings update

If a segment has only one domain concern, the filename may match the slice name (e.g., features/auth/model/auth.ts).

9. Shared layer guide

Shared contains infrastructure with no business logic. It is organized by segments only (no slices). Segments within shared may import from each other.

Allowed in shared:

  • ui/: UI kit (Button, Input, Modal, Card)
  • lib/: Utilities (formatDate, debounce, classnames)
  • api/: API client, route constants, CRUD helpers, base types
  • auth/: Auth tokens, login utilities, session management
  • config/: Environment variables, app settings
  • Assets live with the code that uses them, not in an assets/ segment.

See references/asset-handling.md.

Shared may contain application-aware code: route constants, API endpoints, branding assets, and transport types such as ProductDTO. It must never hold the business rules an entity or feature owns, nor import from those layers.

10. Conditional references

Read the following reference files only when the specific situation applies. Do not preload all references.

  • When reviewing or reorganizing folder and file structure that already

exists, deciding what goes inside a layer or slice, deciding where a page layout belongs, routing widget-like code to another layer, or grouping closely related slices into a parent folder for navigation (e.g., "where does this folder go", "how do I group these payment entities"): → Read references/layer-structure.md

  • When setting up a new project from scratch (e.g., "set up an FSD

project", "start a new app with FSD"), or when asked whether to add entities or features yet, or to show how a structure earns each layer over time rather than its finished shape: → Read references/growth-walkthrough.md

  • When resolving cross-import issues between slices on the same layer,

evaluating the @x pattern, choosing between Strategy A/B/C/D for features and widgets, or deciding whether boundaries should be merged: → Read references/cross-import-patterns.md

  • When deciding whether to create or remove an entity, dealing with too

many entities, evaluating whether to skip the entities layer entirely, placing CRUD operations, or isolating business contexts to avoid @x chains: → Read references/excessive-entities.md

  • When deciding where to place static assets (images, icons, fonts,

PDFs, stylesheets) for a single slice, for sharing across slices, or globally: → Read references/asset-handling.md

  • When migrating from FSD v2.0 to v2.1, converting a non-FSD codebase to

FSD, phasing out an existing widgets layer, or deprecating the processes layer: → Read references/migration-guide.md

  • When integrating FSD with a specific framework (Next.js with App Router

or Pages Router, React Router, Nuxt, Vite, Astro) for wiring routes to FSD pages, placing proxy/middleware and instrumentation files, structuring API route handlers, or configuring path aliases: → Read references/framework-integration.md

  • **When implementing authentication, type definitions, or API request

handling** as concrete code within FSD structure (token storage, login flow, DTO placement, where a request function lives): → Read references/auth-and-api.md

  • When wiring state management (Redux slices, TanStack Query / React

Query, including query factories, infinite scroll, Suspense mode, and useMutationState) into FSD structure: → Read references/state-management.md