feature-sliced-design — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited feature-sliced-design (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Source: fsd.how | Strictness can be adjusted based on project scale and team context.
FSD v2.1 core principle: "Start simple, extract when needed."
Place code in pages/ first. Duplication across pages is acceptable and does not automatically require extraction to a lower layer. Extract only when the same code is currently being used in multiple places (not hypothetically), the usages do not always change together, and the boundary has a focused responsibility.
Not all layers are required. Most projects can start with only shared/, pages/, and app/. Add widgets/, features/, entities/ only when they provide clear value. Do not create empty layer folders "just in case."
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/ → Large composite UI blocks reused across multiple pages
features/ → Reusable user interactions (only when used in 2+ places)
entities/ → Reusable business domain models (only when used in 2+ places)
shared/ → Infrastructure with no business logic (UI kit, utils, API client)Import rule: A module may only import from layers strictly below it. Cross-imports between slices on the same layer are forbidden.
// ✅ 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 → featuresNote: The processes/ layer is deprecated in v2.1. For migration details, read references/migration-guide.md.
When writing new code, follow this tree:
Step 1: Where is this code used?
pages/ slice.in each page is also valid.
(Steiger: insignificant-slice).
Step 2: Is it reusable infrastructure with no business logic?
shared/ui/shared/lib/shared/api/ or shared/config/shared/auth/shared/api/Step 3: Is it a complete user action currently used in multiple places, with stable boundaries?
features/Step 4: Is it a business domain model currently used in multiple places, with stable boundaries?
entities/Step 5: Is it app-wide configuration?
app/Golden Rule: When in doubt, keep it in `pages/`. Extract only when the same code is actively used in multiple places and the boundary is clear.
| 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/ProductCard.tsx |
| Product data fetching | pages/product-detail/api/fetch-product.ts | entities/product/api/ |
| Auth token/session | shared/auth/ (always) | shared/auth/ (always) |
| Auth login form | pages/login/ui/LoginForm.tsx | features/auth/ |
| CRUD operations | shared/api/ (always) | shared/api/ (always) |
| 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 |
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).
app → pages → widgets → features → entities → shared. Upward imports and cross-imports between slices on the same layer are forbidden.
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.
A slice should normally expose its public API through a single index.ts. Ad-hoc customization is not recommended.
If a single index.ts cannot preserve a runtime boundary, add an environment-specific entry point such as index.server.ts. See references/framework-integration.md.
If two slices on the same layer need to share logic, follow the resolution order in Section 7. Do not create direct imports.
Name files after the business domain they represent, not their technical role. Technical-role names like types.ts, utils.ts, helpers.ts mix unrelated domains in a single file and reduce cohesion.
// ❌ Technical-role naming
model/types.ts ← Which types? User? Order? Mixed?
model/utils.ts
// ✅ Domain-based naming
model/user.ts ← User types + related logic
model/order.ts ← Order types + related logic
api/fetch-profile.ts ← Clear purposeShared contains only infrastructure: UI kit, utilities, API client setup, route constants, assets. Business calculations, domain rules, and workflows belong in entities/ or higher layers.
// ❌ Business logic in shared
// shared/lib/userHelpers.ts
export const calculateUserReputation = (user) => { ... };
// ✅ Move to the owning domain
// entities/user/lib/reputation.ts
export const calculateUserReputation = (user) => { ... };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:
Evolution pattern: Start with everything in pages/profile/. When the same user data is being consumed by another page (not hypothetically), extract the shared model to entities/user/. Keep page-specific API calls and UI in the page.
The entities layer is highly accessible (almost every other layer can import from it), so changes propagate widely.
shared/ + pages/ + app/ is valid FSD.Thin-client apps rarely need entities.
entities only when the same code is currently used by multiple consumers and the boundary is stable.
in shared/api and logic in the current slice's model/ segment may be sufficient.
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.
// ✅ 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:
// + widgets/ ← UI blocks currently reused across multiple pages
// + features/ ← User interactions currently reused across multiple pages
// + entities/ ← Domain models currently reused across pages or featuresSteiger is the official FSD linter. Key rules:
if only one page uses it.
many slices.
npm install -D @feature-sliced/steiger
npx steiger srcplace belong in that place.
shared/api/. Consider entities onlyfor complex transactional logic.
belong in shared/auth/ or shared/api/.
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–D (see Section 7).
page should stay in that page.
(see Rule 4-4).
other entities. If you add UI segments to entities, only import them from higher layers (features, widgets, pages), never from other entities.
should be split into focused slices (e.g., split user-management/ into auth/, profile-edit/, password-reset/).
to the code that uses them. See references/asset-handling.md.
Cross-imports are a code smell, not an absolute prohibition. The right strategy depends on the layer and the situation.
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.
In features and widgets, choose based on context:
entities/, keep UI in features/widgets.
imports both slices and connects them via render props, slots, or DI.
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–D above.
Cross-imports are dependencies that are generally best avoided, but sometimes used intentionally. Strictness varies by project context:
cross-imports may be a pragmatic speed trade-off.
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.
Segments group code within a slice by technical purpose:
within these layers may import from each other.
each slice.
the same layer for navigation purposes only. The group has no segments and no public API. See references/layer-structure.md for details.
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 updateIf a segment has only one domain concern, the filename may match the slice name (e.g., features/auth/model/auth.ts).
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 typesauth/: Auth tokens, login utilities, session managementconfig/: Environment variables, app settingsassets/: Branding assets shared across the app (use sparingly; seereferences/asset-handling.md)
Shared may contain application-aware code (route constants, API endpoints, branding assets, common types). It must never contain business logic, feature-specific code, or entity-specific code.
app → pages → widgets → features → entities → sharedapp/ + pages/ + shared/used across multiple pages, features, or widgets, with stable boundaries.
across multiple pages or widgets, with stable boundaries.
reason in code (comment or ADR).
@x is anecessary compromise, not recommended.
(push to entities), C (compose from upper layer), or D (Public API). The @x notation is for entities only.
user.ts, order.ts). Never technical-role(types.ts, utils.ts).
shared/ui/; global stylesheets and fonts go to app/.
has no segments and no public API.
references/migration-guide.md.Read the following reference files only when the specific situation applies. Do not preload all references.
FSD layers and slices, including grouping closely related slices into a parent folder for navigation (e.g., "set up project structure", "where does this folder go", "how do I group these payment entities"): → Read references/layer-structure.md
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
many entities, evaluating whether to skip the entities layer entirely, placing CRUD operations, deciding where authentication data belongs, or isolating business contexts to avoid @x chains: → Read references/excessive-entities.md
PDFs, stylesheets) for a single slice, for sharing across slices, or globally: → Read references/asset-handling.md
FSD, or deprecating the processes layer: → Read references/migration-guide.md
or Pages Router, Nuxt, Vite, CRA, Astro) for wiring routes to FSD pages, placing middleware/instrumentation files, structuring API route handlers, or configuring path aliases: → Read references/framework-integration.md
handling, type definitions, or state management (Redux, TanStack Query / React Query, including query factories, infinite scroll, Suspense mode, and useMutationState) within FSD structure: → Read references/practical-examples.md Note: If you already loaded layer-structure.md in this conversation, avoid loading this file simultaneously. Address structure first, then load patterns in a follow-up step if needed.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.