📖 Guide
Next.js — Complete Reference
Next.js App Router cheat sheet covering routing, data fetching, server components, API routes, middleware, and deployment.
92 commands across 11 categories
Project StructureRouting (App Router)Pages & LayoutsData FetchingServer ComponentsAPI RoutesMiddlewareImage & FontConfigurationDeploymentCommon Patterns
Project Structure
| Command | Description |
|---|---|
npx create-next-app@latest my-app | Create a new Next.js project with interactive setup |
app/ | App Router directory (routes, layouts, pages) |
app/layout.tsx | Root layout — wraps all pages, required |
app/page.tsx | Root page — renders at / |
app/loading.tsx | Loading UI shown while route segment loads |
app/error.tsx | Error boundary for a route segment |
app/not-found.tsx | Custom 404 page |
app/global-error.tsx | Global error boundary (wraps root layout) |
public/ | Static files served at / (images, favicon, etc.) |
next.config.js | Next.js configuration file |
Routing (App Router)
| Command | Description |
|---|---|
app/about/page.tsx | Creates route /about |
app/blog/[slug]/page.tsxe.g. /blog/my-post -> params.slug = 'my-post' | Dynamic route segment |
app/shop/[...slug]/page.tsxe.g. /shop/a/b/c -> params.slug = ['a','b','c'] | Catch-all route |
app/shop/[[...slug]]/page.tsx | Optional catch-all (also matches /shop) |
app/(marketing)/about/page.tsx | Route group — organize without affecting URL path |
app/@modal/page.tsx | Parallel route (named slot) |
app/feed/(..)photo/[id]/page.tsx | Intercepting route — intercept navigation from another segment |
import { redirect } from 'next/navigation';e.g. redirect('/login'); | Server-side redirect |
import { useRouter } from 'next/navigation';e.g. router.push('/dashboard'); | Client-side navigation hook |
import Link from 'next/link';e.g. <Link href="/about">About</Link> | Client-side link with prefetching |
Pages & Layouts
| Command | Description |
|---|---|
export default function Layout({ children }) { } | Layout component — wraps child routes, preserved on navigation |
export default function Page() { } | Page component — unique UI for a route |
export default function Template({ children }) { } | Template — like layout but re-mounts on navigation |
export const metadata = { title: 'Home' }; | Static metadata for a page (title, description, og) |
export async function generateMetadata({ params }) { } | Dynamic metadata based on route params |
export default function Loading() { } | Suspense loading state for a route segment |
'use client'; | Mark a component as a Client Component (enables hooks, events) |
export default function Default() { } | Default fallback for parallel routes (default.tsx) |
Data Fetching
| Command | Description |
|---|---|
const data = await fetch(url); | Fetch data in Server Components (auto-deduped) |
fetch(url, { cache: 'force-cache' }) | Cache response indefinitely (static data) |
fetch(url, { cache: 'no-store' }) | Disable caching (always fresh data) |
fetch(url, { next: { revalidate: 60 } }) | Revalidate cached data every 60 seconds (ISR) |
fetch(url, { next: { tags: ['posts'] } }) | Tag cache entries for on-demand revalidation |
import { revalidateTag } from 'next/cache';e.g. revalidateTag('posts'); | Revalidate all entries with a cache tag |
import { revalidatePath } from 'next/cache';e.g. revalidatePath('/blog'); | Revalidate a specific path |
import { unstable_cache } from 'next/cache'; | Cache function results (not just fetch) |
export async function generateStaticParams() { } | Pre-render dynamic routes at build time |
Server Components
| Command | Description |
|---|---|
async function Page() { const data = await db.query(); } | Server Components can be async and fetch data directly |
import { cookies } from 'next/headers';e.g. const cookieStore = await cookies(); | Read cookies in Server Components |
import { headers } from 'next/headers'; | Read request headers in Server Components |
import 'server-only'; | Ensure a module is never bundled into client code |
'use server'; | Mark a function as a Server Action (callable from client) |
export async function createPost(formData: FormData) { } | Server Action — runs on server, callable from form/client |
<form action={createPost}> | Use a Server Action as a form action (progressive enhancement) |
import { useFormStatus } from 'react-dom'; | Get pending state of a parent form (client component) |
API Routes
| Command | Description |
|---|---|
app/api/users/route.ts | Route Handler file — API endpoint at /api/users |
export async function GET(request: Request) { } | Handle GET requests |
export async function POST(request: Request) { } | Handle POST requests |
return Response.json({ data }) | Return a JSON response |
return new Response(body, { status: 201 }) | Return a custom response with status |
const body = await request.json(); | Parse JSON request body |
const { searchParams } = new URL(request.url); | Access query parameters |
export const dynamic = 'force-dynamic'; | Opt out of static rendering for a route handler |
Middleware
| Command | Description |
|---|---|
middleware.ts | Middleware file at project root — runs before every matched route |
import { NextResponse } from 'next/server'; | Utility for creating middleware responses |
NextResponse.next() | Continue to the route (pass-through) |
NextResponse.redirect(new URL('/login', request.url)) | Redirect the request |
NextResponse.rewrite(new URL('/proxy', request.url)) | Rewrite the URL without redirect |
export const config = { matcher: ['/dashboard/:path*'] }; | Limit middleware to specific paths |
request.cookies.get('token') | Read cookies in middleware |
response.headers.set('x-custom', 'value') | Set response headers in middleware |
Image & Font
| Command | Description |
|---|---|
import Image from 'next/image'; | Optimized image component with lazy loading |
<Image src="/photo.jpg" width={800} height={600} alt="Photo" /> | Display a local or remote image with dimensions |
import img from './photo.png'; | Static import for automatic width/height/blur placeholder |
<Image src={img} placeholder="blur" alt="Photo" /> | Show blur placeholder while loading |
<Image src="/hero.jpg" fill alt="Hero" className="object-cover" /> | Fill parent container (replaces layout=fill) |
import { Inter } from 'next/font/google'; | Load a Google Font with zero layout shift |
const inter = Inter({ subsets: ['latin'] }); | Configure font subset and options |
import localFont from 'next/font/local'; | Load a local font file |
Configuration
| Command | Description |
|---|---|
/** @type {import('next').NextConfig} */ | Type annotation for next.config.js |
images: { remotePatterns: [{ hostname: 'cdn.example.com' }] } | Allow external image domains |
redirects: async () => [{ source, destination, permanent }] | Configure URL redirects |
rewrites: async () => [{ source: '/api/:path*', destination: 'http://backend/:path*' }] | Proxy/rewrite URLs |
env: { CUSTOM_VAR: 'value' } | Expose environment variables to the browser |
output: 'standalone' | Create a standalone build for Docker deployment |
experimental: { serverActions: { bodySizeLimit: '2mb' } } | Configure experimental features |
.env.local | Local environment variables (git-ignored, loaded automatically) |
Deployment
| Command | Description |
|---|---|
next build | Create a production build |
next start | Start the production server |
next dev --turbo | Start dev server with Turbopack (faster) |
next lint | Run ESLint with Next.js rules |
next info | Print system info for bug reports |
output: 'export'e.g. // in next.config.js | Static HTML export (no server required) |
ANALYZE=true next build | Analyze bundle size (requires @next/bundle-analyzer) |
Common Patterns
| Command | Description |
|---|---|
import { useSearchParams } from 'next/navigation'; | Access URL search params in client components |
import { usePathname } from 'next/navigation'; | Get the current pathname in client components |
import { notFound } from 'next/navigation';e.g. if (!post) notFound(); | Trigger the not-found page |
export const dynamic = 'force-dynamic'; | Force dynamic rendering for a page |
export const revalidate = 60; | Set page-level ISR revalidation (seconds) |
import { Suspense } from 'react';e.g. <Suspense fallback={<Loading />}><AsyncComponent /></Suspense> | Wrap async components for streaming |
import { cache } from 'react';e.g. const getUser = cache(async (id) => db.user.find(id)); | Deduplicate data fetching across components |
import dynamic from 'next/dynamic';e.g. const Chart = dynamic(() => import('./Chart'), { ssr: false }); | Dynamically import a component (lazy load) |
📖 Free, searchable command reference. Bookmark this page for quick access.