📂File-Based Routing
app/page.tsxRoute UI component
app/layout.tsxPersistent layout
app/loading.tsxLoading state (Suspense)
app/error.tsxError boundary
app/not-found.tsx404 page
app/[id]/page.tsxDynamic route
app/[...slug]/page.tsxCatch-all route
app/(group)/page.tsxRoute group (no URL)
app/_private/Excluded from routing
app/@modal/page.tsxParallel route
app/(.)photo/page.tsxIntercepting route
🖥️Server vs Client Components
Default: Server ComponentNo JS sent to client
'use client'Client Component directive
'use server'Server Action marker
Can't use hooks in ServerUse Client for hooks
Can fetch data in Serverasync/await directly
Pass Server data as propsBridge pattern
Boundary: import server in clientError: not allowed
Children can be serverComposition pattern
🔄Data Fetching
async function Page() { const d = await fetch() }Server fetch
fetch(url, { cache: 'no-store' })Dynamic (SSR)
fetch(url, { next: { revalidate: 60 } })ISR
fetch(url)Static by default
unstable_cache(fn)Cache server function
generateStaticParams()Static params (SSG)
use(promise)Client async read
SWR / React QueryClient-side fetching
⚡Server Actions
'use server' in functionMark as server action
async function action(data) {}Define action
<form action={action}>Native form action
useFormStatus()Pending state
useActionState(action, init)Action + state
revalidatePath('/path')Invalidate cache
revalidateTag('tag')Invalidate by tag
redirect('/url')Server-side redirect
🔍Metadata & SEO
export const metadata: Metadata = {}Static metadata
export async function generateMetadata()Dynamic metadata
title / description / keywordsBasic SEO fields
openGraph: { title, image }OG metadata
twitter: { card, title }Twitter cards
robots: { index: false }Crawler control
icons: { icon, apple }Favicon
metadataBase: new URL('https://...')Base URL
🖼️Image & Font Optimization
import Image from 'next/image'Optimized image
<Image src fill alt/>Fill container
priorityLCP image (eager load)
sizes='(max-width:768px) 100vw'Responsive sizes
blurDataURL / placeholder='blur'Blur-up loading
import { GeistSans } from 'geist'Variable font
localFont({ src:'...' })Self-hosted font
className={font.variable}Apply font
🧭Navigation & Routing
import Link from 'next/link'Client navigation
<Link href='/about'>Link component
<Link prefetch={false}>Disable prefetch
useRouter()Programmatic nav (client)
router.push('/url')Navigate programmatically
router.refresh()Refresh server data
usePathname()Current path
useSearchParams()Query string
useParams()Dynamic params
redirect('/url')Server redirect
permanentRedirect()301 redirect
🔌API Routes & Middleware
app/api/route.tsAPI route handler
export async function GET(req)Handle GET
export async function POST(req)Handle POST
NextResponse.json({ data })JSON response
NextResponse.redirect(url)Redirect response
req.json() / req.text()Parse body
middleware.ts (root)Middleware file
config.matcher = ['/api/:path*']Route matching
NextResponse.next()Continue request
🚀Caching & Performance
generateStaticParamsPre-render dynamic routes
Suspense boundariesStreaming SSR
loading.tsxAuto Suspense boundary
next/dynamicLazy load component
dynamic('...', { ssr: false })Client-only component
export const dynamic = 'force-dynamic'Opt-out static
export const revalidate = 3600Segment revalidation
after(fn)Post-response hook