141 lines
3.4 KiB
Markdown
141 lines
3.4 KiB
Markdown
# File Conventions
|
|
|
|
Next.js App Router uses file-based routing with special file conventions.
|
|
|
|
## Project Structure
|
|
|
|
Reference: https://nextjs.org/docs/app/getting-started/project-structure
|
|
|
|
```
|
|
app/
|
|
├── layout.tsx # Root layout (required)
|
|
├── page.tsx # Home page (/)
|
|
├── loading.tsx # Loading UI
|
|
├── error.tsx # Error UI
|
|
├── not-found.tsx # 404 UI
|
|
├── global-error.tsx # Global error UI
|
|
├── route.ts # API endpoint
|
|
├── template.tsx # Re-rendered layout
|
|
├── default.tsx # Parallel route fallback
|
|
├── blog/
|
|
│ ├── page.tsx # /blog
|
|
│ └── [slug]/
|
|
│ └── page.tsx # /blog/:slug
|
|
└── (group)/ # Route group (no URL impact)
|
|
└── page.tsx
|
|
```
|
|
|
|
## Special Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `page.tsx` | UI for a route segment |
|
|
| `layout.tsx` | Shared UI for segment and children |
|
|
| `loading.tsx` | Loading UI (Suspense boundary) |
|
|
| `error.tsx` | Error UI (Error boundary) |
|
|
| `not-found.tsx` | 404 UI |
|
|
| `route.ts` | API endpoint |
|
|
| `template.tsx` | Like layout but re-renders on navigation |
|
|
| `default.tsx` | Fallback for parallel routes |
|
|
|
|
## Route Segments
|
|
|
|
```
|
|
app/
|
|
├── blog/ # Static segment: /blog
|
|
├── [slug]/ # Dynamic segment: /:slug
|
|
├── [...slug]/ # Catch-all: /a/b/c
|
|
├── [[...slug]]/ # Optional catch-all: / or /a/b/c
|
|
└── (marketing)/ # Route group (ignored in URL)
|
|
```
|
|
|
|
## Parallel Routes
|
|
|
|
```
|
|
app/
|
|
├── @analytics/
|
|
│ └── page.tsx
|
|
├── @sidebar/
|
|
│ └── page.tsx
|
|
└── layout.tsx # Receives { analytics, sidebar } as props
|
|
```
|
|
|
|
## Intercepting Routes
|
|
|
|
```
|
|
app/
|
|
├── feed/
|
|
│ └── page.tsx
|
|
├── @modal/
|
|
│ └── (.)photo/[id]/ # Intercepts /photo/[id] from /feed
|
|
│ └── page.tsx
|
|
└── photo/[id]/
|
|
└── page.tsx
|
|
```
|
|
|
|
Conventions:
|
|
- `(.)` - same level
|
|
- `(..)` - one level up
|
|
- `(..)(..)` - two levels up
|
|
- `(...)` - from root
|
|
|
|
## Private Folders
|
|
|
|
```
|
|
app/
|
|
├── _components/ # Private folder (not a route)
|
|
│ └── Button.tsx
|
|
└── page.tsx
|
|
```
|
|
|
|
Prefix with `_` to exclude from routing.
|
|
|
|
## Middleware / Proxy
|
|
|
|
### Next.js 14-15: `middleware.ts`
|
|
|
|
```ts
|
|
// middleware.ts (root of project)
|
|
import { NextResponse } from 'next/server';
|
|
import type { NextRequest } from 'next/server';
|
|
|
|
export function middleware(request: NextRequest) {
|
|
// Auth, redirects, rewrites, etc.
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ['/dashboard/:path*', '/api/:path*'],
|
|
};
|
|
```
|
|
|
|
### Next.js 16+: `proxy.ts`
|
|
|
|
Renamed for clarity - same capabilities, different names:
|
|
|
|
```ts
|
|
// proxy.ts (root of project)
|
|
import { NextResponse } from 'next/server';
|
|
import type { NextRequest } from 'next/server';
|
|
|
|
export function proxy(request: NextRequest) {
|
|
// Same logic as middleware
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const proxyConfig = {
|
|
matcher: ['/dashboard/:path*', '/api/:path*'],
|
|
};
|
|
```
|
|
|
|
| Version | File | Export | Config |
|
|
|---------|------|--------|--------|
|
|
| v14-15 | `middleware.ts` | `middleware()` | `config` |
|
|
| v16+ | `proxy.ts` | `proxy()` | `proxyConfig` |
|
|
|
|
**Migration**: Run `npx @next/codemod@latest upgrade` to auto-rename.
|
|
|
|
## File Conventions Reference
|
|
|
|
Reference: https://nextjs.org/docs/app/api-reference/file-conventions
|