---
id: wiki-2026-0508-folder-structure-best-practices
title: Folder Structure Best Practices
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Project Structure, Code Organization, Frontend Folder Layout]
duplicate_of: none
source_trust_level: A
confidence_score: 0.85
verification_status: applied
tags: [architecture, folder-structure, frontend, project-organization]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: typescript
  framework: react-next
---

# Folder Structure Best Practices

## 매 한 줄
> **"매 folder structure 의 골 — colocation by feature, not by file-type"**. 매 modern frontend (2026) 의 favored: feature-sliced design, screaming architecture, Next.js app router colocation. 매 type-based folders (`components/`, `utils/`) 의 rejection — feature 의 boundary 의 unclear.

## 매 핵심

### 매 Type-based (anti) vs Feature-based (good)
- **Type-based**: `/components`, `/hooks`, `/utils`, `/services`, `/types` — every change touches 5 folders.
- **Feature-based**: `/features/checkout/{components,hooks,api,types}` — change scope = single folder.

### 매 Levels of Hierarchy
1. **Routes / pages** (Next.js `app/`, Remix `routes/`).
2. **Features** (`features/<feature>/...`) — domain boundaries.
3. **Shared** (`lib/`, `shared/`, `ui/`) — cross-feature reusables.
4. **Entities/domain** (Feature-Sliced: `entities/user`, `entities/cart`).

### 매 Boundaries
- Features 의 each other 의 import X (cross-feature 의 shared layer 의 통과).
- Lower layers 의 higher 의 import X (UI 의 feature 의 import X).
- 매 ESLint `no-restricted-imports` 또는 `eslint-plugin-boundaries` 의 enforce.

### 매 응용
1. Next.js 15 app router project.
2. Vite + React SPA.
3. Monorepo (Turborepo, Nx).
4. React Native app.

## 💻 패턴

### Feature-Sliced (recommended 2026)
```
src/
├── app/                    # app entry, providers, global styles
├── pages/                  # (or routes/) page-level composition
├── features/               # business actions (toggle-cart, send-comment)
│   └── send-comment/
│       ├── ui/
│       ├── model/          # state, hooks
│       ├── api/
│       └── index.ts        # public API
├── entities/               # business entities (user, post, cart)
│   └── user/
│       ├── ui/
│       ├── model/
│       └── api/
├── shared/                 # reusable, domain-agnostic
│   ├── ui/                 # buttons, inputs (design system)
│   ├── lib/                # utilities
│   ├── api/                # base http client
│   └── config/
└── widgets/                # composite UI blocks (Header, Sidebar)
```

### Next.js 15 App Router (colocation)
```
app/
├── layout.tsx
├── page.tsx
├── (marketing)/            # route group, no URL segment
│   └── about/page.tsx
├── dashboard/
│   ├── layout.tsx
│   ├── page.tsx
│   ├── _components/        # private (underscore = not routable)
│   │   └── Sidebar.tsx
│   ├── settings/
│   │   ├── page.tsx
│   │   └── actions.ts      # server actions
│   └── api/
│       └── route.ts
src/
├── lib/                    # shared utilities, db, auth
├── components/ui/          # design system
└── features/               # cross-page features
```

### Vite + React SPA (mid-size)
```
src/
├── main.tsx
├── App.tsx
├── routes/                 # react-router routes
├── features/
│   └── auth/
│       ├── components/
│       ├── hooks/
│       ├── api.ts
│       ├── types.ts
│       └── index.ts
├── components/ui/          # design system
├── hooks/                  # generic hooks
├── lib/
└── types/
```

### Monorepo (Turborepo)
```
apps/
├── web/                    # Next.js app
├── mobile/                 # Expo
└── docs/
packages/
├── ui/                     # shared design system
├── config/                 # eslint, ts, tailwind presets
├── api/                    # tRPC / generated client
└── db/                     # Prisma schema
```

### Feature Public API (barrel)
```ts
// features/checkout/index.ts — explicit exports only
export { CheckoutPage } from './ui/CheckoutPage';
export { useCheckout } from './model/useCheckout';
export type { CheckoutState } from './model/types';
// internals (api/, model/internal) NOT re-exported
```

### Boundary Enforcement (eslint-plugin-boundaries)
```js
// eslint.config.js
import boundaries from 'eslint-plugin-boundaries';

export default [{
  plugins: { boundaries },
  settings: {
    'boundaries/elements': [
      { type: 'shared',   pattern: 'src/shared/*' },
      { type: 'entity',   pattern: 'src/entities/*' },
      { type: 'feature',  pattern: 'src/features/*' },
      { type: 'widget',   pattern: 'src/widgets/*' },
      { type: 'page',     pattern: 'src/pages/*' },
    ],
  },
  rules: {
    'boundaries/element-types': ['error', {
      default: 'disallow',
      rules: [
        { from: 'page',    allow: ['widget', 'feature', 'entity', 'shared'] },
        { from: 'widget',  allow: ['feature', 'entity', 'shared'] },
        { from: 'feature', allow: ['entity', 'shared'] },
        { from: 'entity',  allow: ['shared'] },
        { from: 'shared',  allow: ['shared'] },
      ],
    }],
  },
}];
```

### TS Path Aliases
```json
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@shared/*": ["src/shared/*"],
      "@features/*": ["src/features/*"]
    }
  }
}
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| Small SPA (<20 components) | Flat or simple `components/` + `pages/` |
| Mid-size (20-200) | Feature-based (`features/` + `shared/`) |
| Large / team scale | Feature-Sliced Design + boundary lint |
| Next.js project | App router colocation + `src/features/` |
| Monorepo | Turborepo `apps/` + `packages/` |

**기본값**: feature-based + shared layer + ESLint boundary enforcement.

## 🔗 Graph
- 부모: [[Software Architecture]] · [[Large_Frontend_Projects|Frontend Architecture]]
- 변형: [[Feature-Sliced Design]] · [[Atomic Design]]
- 응용: [[Monorepo]] · [[Design System]]
- Adjacent: [[Next.js]] · [[Turborepo]]

## 🤖 LLM 활용
**언제**: project structure 의 design, refactor folder layout, boundary rule 의 setup.
**언제 X**: tiny prototype — overhead 의 not worth.

## ❌ 안티패턴
- **Type-based root** (`/components`, `/hooks`, `/utils`): scales poorly.
- **Deeply nested barrels**: circular import / slow build.
- **God `utils/`**: dump folder. 매 specific domain 의 split.
- **Cross-feature imports**: feature isolation 의 break — shared 의 use.
- **`index.ts` 의 every file의 leak**: tree-shaking break, public API 의 unclear.
- **`pages/` 안에 business logic**: route 는 thin, feature 의 delegate.

## 🧪 검증 / 중복
- Verified (Feature-Sliced Design docs, Next.js project structure docs, Bulletproof React).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — folder structure best practices full content |
