Files
stack/packages/mosaic/framework/skills/next-best-practices/file-conventions.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
2026-08-19 14:37:17 -05:00

3.7 KiB

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

// 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:

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