Get the FREE Ultimate OpenClaw Setup Guide →

feature-slicing

npx machina-cli add skill ccheney/robust-skills/feature-slicing --openclaw
Files (1)
SKILL.md
8.3 KB

Feature-Sliced Design Architecture

Frontend architecture methodology with strict layer hierarchy and import rules for scalable, maintainable applications. FSD organizes code by business domain rather than technical role.

Official Docs: feature-sliced.design | GitHub: feature-sliced


THE IMPORT RULE (Critical)

Modules can ONLY import from layers strictly below them. Never sideways or upward.

app → pages → widgets → features → entities → shared
 ↓      ↓        ↓          ↓          ↓         ✓
 ✓      ✓        ✓          ✓          ✓      (external only)
ViolationExampleFix
Cross-slice (same layer)features/authfeatures/userExtract to entities/ or shared/
Upward importentities/userfeatures/authMove shared code down
Shared importing upshared/entities/Shared has NO internal deps

Exception: app/ and shared/ have no slices, so internal cross-imports are allowed within them.


Layer Hierarchy

LayerPurposeHas SlicesRequired
app/Initialization, routing, providers, global stylesNoYes
pages/Route-based screens (one slice per route)YesYes
widgets/Complex reusable UI blocks (header, sidebar)YesNo
features/User interactions with business value (login, checkout)YesNo
entities/Business domain models (user, product, order)YesNo
shared/Project-agnostic infrastructure (UI kit, API client, utils)NoYes

Minimal setup: app/, pages/, shared/ — add other layers as complexity grows.


Quick Decision Trees

"Where does this code go?"

Code Placement:
├─ App-wide config, providers, routing    → app/
├─ Full page / route component            → pages/
├─ Complex reusable UI block              → widgets/
├─ User action with business value        → features/
├─ Business domain object (data model)    → entities/
└─ Reusable, domain-agnostic code         → shared/

"Feature or Entity?"

Entity (noun)Feature (verb)
user — user data modelauth — login/logout actions
product — product infoadd-to-cart — adding to cart
comment — comment datawrite-comment — creating comments
order — order recordcheckout — completing purchase

Rule: Entities represent THINGS with identity. Features represent ACTIONS with side effects.

"Which segment?"

Segments (within a slice):
├─ ui/      → React components, styles
├─ api/     → Backend calls, data fetching, DTOs
├─ model/   → Types, schemas, stores, business logic
├─ lib/     → Slice-specific utilities
└─ config/  → Feature flags, constants

Naming: Use purpose-driven names (api/, model/) not essence-based (hooks/, types/).


Directory Structure

src/
├── app/                    # App layer (no slices)
│   ├── providers/          # React context, QueryClient, theme
│   ├── routes/             # Router configuration
│   └── styles/             # Global CSS, theme tokens
├── pages/                  # Page slices
│   └── {page-name}/
│       ├── ui/             # Page components
│       ├── api/            # Loaders, server actions
│       ├── model/          # Page-specific state
│       └── index.ts        # Public API
├── widgets/                # Widget slices
│   └── {widget-name}/
│       ├── ui/             # Composed UI
│       └── index.ts
├── features/               # Feature slices
│   └── {feature-name}/
│       ├── ui/             # Feature UI
│       ├── api/            # Feature API calls
│       ├── model/          # State, schemas
│       └── index.ts
├── entities/               # Entity slices
│   └── {entity-name}/
│       ├── ui/             # Entity UI (Card, Avatar)
│       ├── api/            # CRUD operations
│       ├── model/          # Types, mappers, validation
│       └── index.ts
└── shared/                 # Shared layer (no slices)
    ├── ui/                 # Design system components
    ├── api/                # API client, interceptors
    ├── lib/                # Utilities (dates, validation)
    ├── config/             # Environment, constants
    ├── routes/             # Route path constants
    └── i18n/               # Translations

Public API Pattern

Every slice MUST expose a public API via index.ts. External code imports ONLY from this file.

// entities/user/index.ts
export { UserCard } from './ui/UserCard';
export { UserAvatar } from './ui/UserAvatar';
export { getUser, updateUser } from './api/userApi';
export type { User, UserRole } from './model/types';
export { userSchema } from './model/schema';
// ✅ Correct
import { UserCard, type User } from '@/entities/user';

// ❌ Wrong
import { UserCard } from '@/entities/user/ui/UserCard';

Avoid wildcard exports — they expose internals and harm tree-shaking:

// ❌
export * from './ui';

// ✅
export { UserCard } from './ui/UserCard';

Cross-Entity References (@x Notation)

When entities legitimately reference each other, use the @x notation:

entities/
├── product/
│   ├── @x/
│   │   └── order.ts    # API specifically for order entity
│   └── index.ts
└── order/
    └── model/types.ts  # Imports from product/@x/order
// entities/product/@x/order.ts
export type { ProductId } from '../model/types';

// entities/order/model/types.ts
import type { ProductId } from '@/entities/product/@x/order';

Guidelines: Keep cross-imports minimal. Consider merging entities if references are extensive.


Anti-Patterns

Anti-PatternProblemFix
Cross-slice importfeatures/afeatures/bExtract shared logic down
Generic segmentscomponents/, hooks/Use ui/, lib/, model/
Wildcard exportsexport * from './button'Explicit named exports
Business logic in sharedDomain logic in shared/libMove to entities/
Single-use widgetsWidget used by one pageKeep in page slice
Skipping public APIImport from internal pathsAlways use index.ts
Making everything a featureAll interactions as featuresOnly reused actions

TypeScript Configuration

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Reference Documentation

FilePurpose
references/LAYERS.mdComplete layer specifications, flowcharts
references/PUBLIC-API.mdExport patterns, @x notation, tree-shaking
references/IMPLEMENTATION.mdCode patterns: entities, features, React Query
references/NEXTJS.mdApp Router integration, page re-exports
references/MIGRATION.mdIncremental migration strategy
references/CHEATSHEET.mdQuick reference, import matrix

Resources

Official Sources

Community

Source

git clone https://github.com/ccheney/robust-skills/blob/main/skills/feature-slicing/SKILL.mdView on GitHub

Overview

Feature-Sliced Design (FSD) is a frontend architecture that enforces a strict layer hierarchy and import rules to keep code scalable and maintainable. It organizes code by business domain (entities, features, pages, widgets, shared) rather than by technical roles, enabling clearer boundaries and independent slices. This structure reduces cross-dependencies and makes refactoring and scaling easier across React/Next.js/Vue/Remix projects.

How This Skill Works

Code is organized into layers: app, pages, widgets, features, entities, and shared. Each slice can contain segments like ui, api, model, lib, and config, allowing domain-specific organization. The core rule, the Import Rule, requires that modules only import from layers strictly below them; app and shared are special cases with no slices, allowing internal cross-imports.

When to Use It

  • Restructuring a React/Next.js/Vue/Remix project to align with domain-driven slices.
  • Organizing frontend code by business capability to improve maintainability and collaboration.
  • Fixing cross-layer import violations and breaking circular dependencies.
  • Migrating a legacy codebase into a scalable FSD structure with clear module boundaries.
  • Setting up a new frontend project from scratch using a domain-based slice layout (app/pages/widgets/features/entities/shared).

Quick Start

  1. Step 1: Define top-level layers (app/, pages/, widgets/, features/, entities/, shared/).
  2. Step 2: Create a slice for a page/feature and structure its internal folders as ui/, api/, model/, lib/, config/.
  3. Step 3: Enforce the Import Rule and gradually migrate code, validating imports stay within allowed directions.

Best Practices

  • Start with a minimal setup: app/, pages/, shared/ and add layers as needed.
  • Enforce the Import Rule strictly: modules may only import from lower layers.
  • Name slices by domain: use entities/, features/, pages/, widgets/ with consistent ui/api/model segments.
  • Keep domain boundaries stable: entities hold business models, features handle user actions, pages orchestrate routes.
  • Document boundaries and provide a quick-start guide for new team members.

Example Use Cases

  • Migrate a monolithic React app to FSD by creating app/, pages/, shared/ and moving components into the correct slices.
  • Refactor a Next.js app so each route becomes a page slice with ui/api/model inside.
  • Fix import violations by relocating shared logic into shared/ or lower layers and updating imports.
  • Adapt a legacy Vue app to domain-oriented slices with clear segment folders.
  • Implement FSD in a Remix project by separating features, entities, and pages with defined import paths.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers