# Next.js Project Structure Standard

> **Scope:** frontend/nextjs/project-structure
> **Layer:** 2 (on keyword)
> **Keywords:** project structure, folder structure, feature folder, src layout
> **Load When:** creating new files or features

**Verified against:** Next.js 15 (App Router, `src/` layout). Last-verified: 2026-05-20.

---

Feature-based architecture with a shared core. Features are self-contained; shared code is explicit.

## Core Rules

- ALWAYS use feature-based folders: `features/{feature-name}/`
- ALWAYS keep `app/` for routing only — import from `features/`, not the other way
- NEVER import from one feature into another — extract to `components/` or `lib/` if shared
- ALWAYS use `src/` directory (configured in `tsconfig.json` with `@/` alias)
- NEVER put business logic in `components/` — it is presentation only

## Canonical Folder Tree

```
src/
├── app/                                  # Next.js App Router — routes only
│   ├── layout.tsx                        # Root layout + providers
│   ├── page.tsx                          # Home page
│   └── (dashboard)/
│       ├── layout.tsx
│       ├── users/
│       │   ├── page.tsx
│       │   ├── loading.tsx
│       │   └── error.tsx
│       └── billing/
│           └── page.tsx
│
├── features/                             # Domain features
│   └── {feature-name}/
│       ├── components/                   # Feature-specific UI components
│       │   ├── user-list.tsx
│       │   └── user-card.tsx
│       ├── hooks/                        # TanStack Query hooks for this feature
│       │   ├── use-users.ts
│       │   └── use-create-user.ts
│       ├── types/
│       │   ├── user.types.ts             # TypeScript types
│       │   └── user.schemas.ts           # Zod schemas + z.infer<> types
│       └── index.ts                      # Public API — only export what's needed
│
├── components/                           # Shared UI — no business logic
│   ├── ui/                               # shadcn/ui — never edit directly
│   │   ├── button.tsx
│   │   └── card.tsx
│   ├── data-table.tsx
│   ├── page-header.tsx
│   └── empty-state.tsx
│
├── hooks/                                # Shared utility hooks — no API calls
│   ├── use-debounce.ts
│   └── use-media-query.ts
│
├── lib/
│   ├── api-client.ts                     # Typed fetch wrapper for .NET API
│   └── query-client.tsx                  # TanStack Query client + provider
│
├── types/
│   ├── api.ts                            # Shared API shapes: PaginatedResponse<T>, ApiError
│   └── env.d.ts
│
└── env.mjs                               # Zod-validated env vars
```

## Feature Index Pattern

```ts
// features/users/index.ts — explicit public API
export { UserList } from './components/user-list';
export { UserCard } from './components/user-card';
export { useUsers } from './hooks/use-users';
export { useCreateUser } from './hooks/use-create-user';
export type { User, CreateUserInput } from './types/user.types';
```

Import from the index, not deep paths:
```ts
// GOOD
import { UserList, useUsers } from '@/features/users';

// BAD
import { UserList } from '@/features/users/components/user-list';
```

## Feature Boundary Rule

```
app/              → imports from features/ ✓
features/users/   → imports from components/ and lib/ ✓
features/users/   → imports from features/billing/ ✗ (extract shared instead)
components/       → imports from components/ui/ ✓
components/       → imports from features/ ✗
```

---

*MORPH-SPEC by Polymorphism Tech*
