Next.js 29 ▲ Cheatsheet
This cheatsheet covers the App Router (the canonical routing model), core file conventions, data fetching and caching APIs, and the breaking changes introduced in Next.js 16. It reflects the current stable documentation.
File Conventions (App Router)
Every directory under app/ is a route segment. Each segment can carry these special files :
| File | Purpose | Notes |
|---|---|---|
page.tsx | Route UI | Renders inside the nearest layout |
layout.tsx | Shared UI wrapper | Root layout must contain <html> and <body> |
loading.tsx | Suspense fallback | Automatic loading state for the segment |
error.tsx | Error boundary | Must be a Client Component ('use client') |
not-found.tsx | 404 UI | Triggered by notFound() |
route.ts | API endpoint | Replaces pages/api/* |
template.tsx | Re-rendered layout | Unlike layout, re-mounts on navigation |
default.tsx | Parallel route fallback | Required for parallel routes in v16 |
Core Directives
| Directive | Where | Purpose |
|---|---|---|
'use client' | Top of file | Marks a Client Component (hydrates in browser) |
'use server' | Top of file or function | Marks a Server Action (callable from client) |
'use cache' | Top of async function/component | Caches the result (Cache Components) |
Routing & Navigation
| Task | API | Import |
|---|---|---|
| Programmatic navigation | router.push('/path') | next/navigation |
| Read pathname | usePathname() | next/navigation |
| Read search params | useSearchParams() | next/navigation |
| Read route params (Server) | const { id } = await params | Props (async in v15+) |
| Read route params (Client) | useParams() | next/navigation |
| Redirect | redirect('/login') | next/navigation |
| Not found | notFound() | next/navigation |
Dynamic segments: [slug], catch-all [...slug], optional catch-all [[...slug]] .
Data Fetching & Caching
fetch caching defaults (Next.js 15+):
| Pattern | Code | Behavior |
|---|---|---|
| Static | fetch(url, { cache: 'force-cache' }) | Cached at build |
| Revalidated | fetch(url, { next: { revalidate: 3600 } }) | Cached, revalidated every hour |
| Dynamic | fetch(url, { cache: 'no-store' }) | Every request |
| Default (v15+) | fetch(url) | Uncached |
Route segment config:
export const dynamic = 'force-dynamic'; // Always dynamic
export const revalidate = 3600; // ISR: revalidate every hour
Cache Components ('use cache'):
async function BlogPost() {
'use cache';
cacheLife('hours'); // Built-in profile
cacheTag('posts'); // Tag for invalidation
const post = await db.post.findFirst();
return <article>{post.title}</article>;
}
Caching APIs (Next.js 16)
| API | Where | Behavior |
|---|---|---|
revalidateTag(tag, profile) | Anywhere | Stale-while-revalidate; requires 2nd arg in v16 |
updateTag(tag) | Server Actions only | Read-your-writes; immediate refresh |
refresh() | Server Actions only | Refreshes uncached data only |
cacheLife(profile) | Inside 'use cache' | Sets cache duration ('hours', 'days', 'max') |
cacheTag(tag) | Inside 'use cache' | Tags cached content for invalidation |
// v16: second argument required
revalidateTag('posts', 'max'); // ✅
revalidateTag('posts'); // ❌ Deprecated, TypeScript error
// Immediate refresh in Server Action
'use server';
import { updateTag } from 'next/cache';
await db.users.update(id, data);
updateTag(`user-${id}`);
Proxy (Formerly Middleware)
In Next.js 16, middleware.ts was renamed to proxy.ts .
| Aspect | Detail |
|---|---|
| File name | proxy.ts (project root or src/) |
| Export | export function proxy() (named or default) |
| Runtime | Node.js only (Edge not supported) |
| Use case | Optimistic redirects, header modification |
| Not for | Authoritative auth checks or slow data fetching |
// proxy.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function proxy(request: NextRequest) {
const token = request.cookies.get('session')?.value;
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
Server Actions
// app/actions.ts
'use server';
export async function updateProfile(formData: FormData) {
const session = await getSession();
if (!session) throw new Error('Unauthorized'); // Always validate
const name = formData.get('name') as string;
await db.user.update({ where: { id: session.user.id }, data: { name } });
revalidateTag('profile', 'max'); // v16: second arg required
}
Key rule: Server Actions are public endpoints. Always re-validate authentication at the start of every action.
Breaking Changes (v15 → v16)
| Change | Old | New |
|---|---|---|
params type | { id: string } | Promise<{ id: string }> (must await) |
revalidateTag | revalidateTag('tag') | revalidateTag('tag', 'max') |
| Middleware file | middleware.ts | proxy.ts |
| Turbopack | Opt-in (--turbopack) | Default bundler |
| AMP | Supported | Removed |
next lint | Available | Removed; use ESLint directly |
| Node.js | 18+ | 20.9+ |
| TypeScript | 4.x | 5.1+ |
Version Requirements (Next.js 16)
| Dependency | Minimum |
|---|---|
| Node.js | 20.9.0 |
| TypeScript | 5.1.0 |
| React | 19.2 |
| Chrome / Edge | 111+ |
| Safari | 16.4+ |
Common Patterns
| Pattern | Implementation |
|---|---|
| Protected page | const session = await getSession(); if (!session) redirect('/login') |
| Protected action | const session = await getSession(); if (!session) throw new Error('Unauthorized') |
| Lazy-load heavy component | const Chart = dynamic(() => import('./Chart'), { ssr: false }) |
| Image with no CLS | <Image src="/hero.jpg" width={1200} height={600} alt="Hero" /> |
| Font with no CLS | const inter = Inter({ subsets: ['latin'], display: 'swap' }) |
| Metadata | export const metadata: Metadata = { title: 'Page' } |
| Dynamic metadata | export async function generateMetadata({ params }) { ... } |
Quick Commands
# Create new project
npx create-next-app@latest
# Upgrade with guidance
npx next upgrade
# Build (Turbopack default in v16)
next build
# Build with Webpack (opt-out)
next build --webpack
# App Router migration codemod
npx @next/codemod@latest app-router-migration ./pages
Summary
| Area | Key Takeaway |
|---|---|
| Routing | File-system based; page.tsx renders, layout.tsx wraps |
| Components | Server by default; 'use client' for interactivity |
| Data fetching | Colocated in async Server Components; fetch uncached by default since v15 |
| Caching | 'use cache' + cacheLife + cacheTag; revalidateTag requires profile arg in v16 |
| Server Actions | Public endpoints; always re-validate auth |
| Middleware | Renamed to proxy.ts in v16; optimistic checks only |
| Bundle | Turbopack is default in v16 |
Remember: The App Router is not a collection of APIs to memorize—it is a mental model shift. Server Components render on the server and ship zero JS. Client Components hydrate. Server Actions are endpoints. The file system is the router. The caching APIs exist to make the default (dynamic) faster without sacrificing correctness. Learn the boundary rules, and the APIs follow naturally.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!