# Feature Sliced Design

> >

- **Type:** Skill
- **Install:** `agentstack add skill-bbar0n234-learnflow-ai-feature-sliced-design`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Bbar0n234](https://agentstack.voostack.com/s/bbar0n234)
- **Installs:** 0
- **Category:** [Databases](https://agentstack.voostack.com/c/databases)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [Bbar0n234](https://github.com/Bbar0n234)
- **Source:** https://github.com/Bbar0n234/learnflow-ai/tree/main/.claude/skills/feature-sliced-design

## Install

```sh
agentstack add skill-bbar0n234-learnflow-ai-feature-sliced-design
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Feature-Sliced Design (FSD) v2.1

> **Source**: [fsd.how](https://fsd.how) | Strictness can be adjusted based on
> project scale and team context.

---

## 1. Core Philosophy & Layer Overview

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:

```text
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.

```typescript
// ✅ 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 used in only one page → keep it in that page
  (Steiger: `insignificant-slice`).

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

- UI components → `shared/ui/`
- Utility functions → `shared/lib/`
- API client, route constants → `shared/api/` or `shared/config/`
- Auth tokens, session management → `shared/auth/`
- CRUD operations → `shared/api/`

**Step 3: Is it a complete user action currently used in multiple places,
with stable boundaries?**

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

**Step 4: Is it a business domain model currently used in multiple places,
with stable boundaries?**

- 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
same code is actively used in multiple places and the boundary is clear.**

---

## 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/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`           |

---

## 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 and cross-imports between slices on the same layer are
forbidden.

### 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.

```typescript
// ✅ 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.

### Environment-specific public APIs

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`.

### 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. Do not create direct imports.

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

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.

```text
// ❌ 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 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.

```typescript
// ❌ 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) => { ... };
```

---

## 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/`. 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.

### 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.
2. **Do not split slices prematurely.** Keep code in pages. Extract to
   entities only when the same code is currently used by multiple
   consumers and the boundary is stable.
3. **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.
4. **Place CRUD in `shared/api/`.** CRUD is infrastructure, not entities.
5. **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

```text
// ✅ 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 features
```

### 5-4. Validate with the Steiger linter

[Steiger](https://github.com/feature-sliced/steiger) is the official FSD
linter. Key rules:

- **`insignificant-slice`**: Suggests merging an entity/feature into its page
  if only one page uses it.
- **`excessive-slicing`**: Suggests merging or grouping when a layer has too
  many slices.

```bash
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.** Use `shared/api/`. Consider entities only
  for complex transactional logic.
- **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–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, widgets, pages), 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. 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.** Shared domain logic → move to
  `entities/`, keep UI in features/widgets.
- **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–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:

```text
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/`: Branding assets shared across the app (use sparingly; see
  `references/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.

---

## 10. Quick Reference

- **Import direction**: `app → pages → widgets → features → entities → shared`
- **Minimal FSD**: `app/` + `pages/` + `shared/`
- **Create entities when**: the same business domain model is currently
  used across multiple pages, features, or widgets, with stable
  boundaries.
- **Create features when**: the same user interaction is currently used
  across multiple pages or widgets, with stable boundaries.
- **Breaking rules**: Only as an intentional design choice. Document the
  reason in code (comment or ADR).
- **Cross-import resolution (entities)**: Merge boundaries first; `@x` is a
  necessary compromise, not recommended.
- **Cross-import resolution (features/widgets)**: Strategy A (merge), B
  (push to entitie

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Bbar0n234](https://github.com/Bbar0n234)
- **Source:** [Bbar0n234/learnflow-ai](https://github.com/Bbar0n234/learnflow-ai)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-bbar0n234-learnflow-ai-feature-sliced-design
- Seller: https://agentstack.voostack.com/s/bbar0n234
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
