Next.js 13: App Router and Server Components Revolution

App Router vs Pages Router Architecture

Next.js 12 Pages Router: /pages/blog/[id].js → /blog/123 (file-based routing). Next.js 13 App Router: /app/blog/[id]/page.js (same result, nested layouts). Pages Router limitations: shared layout requires wrapping in _app.tsx (difficult to manage multiple layout types), error handling via _error.js (centralized only). App Router nested layouts: /app/layout.js (root), /app/blog/layout.js (blog-specific), /app/blog/[id]/layout.js (post-specific). Each layout wraps nested segments: User sees consistent header (root layout), blog sidebar (blog layout), post-specific metadata (post layout). Layout composition: 3 levels deep is typical, unlimited nesting possible. Automatic code-splitting: each route segment loads separately (no monolithic bundle). Route groups: /app/(auth)/login, /app/(auth)/register → routes NOT in URL, but organize code logically.

React Server Components and Streaming SSR

React Server Components (RSC): render on server, send serialized output to client (not JavaScript). Traditional SSR: render on server, send HTML + JavaScript bundle, hydrate on client (2 downloads, 2 renders). RSC: renders on server, sends result (JSON-like), client receives pre-rendered tree (1 download, no hydration waterfall). Database queries: Server Components call database directly (no API route needed). Example: <BlogPost id={123}> (server component) calls db.query('SELECT * FROM posts WHERE id=123'), renders result, sends to client. No N+1 queries (batched queries on server). Next.js 13 streaming: renderToPipeableStream sends Response chunks as RSC renders. Browser receives chunks progressively: header renders first (~100ms), then sidebar (~200ms), then content (~500ms). User sees page appear incrementally (Progressive Enhancement), instead of waiting 500ms blank page.

Dynamic and Parallel Routes

Dynamic segments: [id] in filename creates dynamic route. Example: /app/product/[id]/page.js matches /product/123, /product/456, etc. generateStaticParams() pre-renders common IDs: generateStaticParams() { return [{id: '1'}, {id: '2'}] } → builds /product/1, /product/2 at build-time (ISR for others). Optional segments: [[...slug]]/page.js matches /, /blog, /blog/react, /blog/react/hooks (catch-all route). Parallel routes: @team and @analytics folders render side-by-side in same layout. Example: dashboard layout shows @team (team members list) + @analytics (charts) + main content (all in parallel). Different URL: /dashboard vs /dashboard?analytics=true render different @analytics component (without changing @team). Use case: Gmail-style: email list + preview panel + sidebar (all update independently).

Image, Font, and Script Optimization

next/image: automatic image optimization. Image component with src, width, height, alt - serves WebP format (70% smaller than JPEG), lazy-loads (load only when visible), responsive. Image component generates srcSet with multiple resolutions (400w, 800w, 1200w). Browser chooses appropriate size. LCP optimization: images load within 2 seconds target. next/font: downloads font files, avoids layout shift (CLS less than 0.1). Example: import Inter from next/font/google, const inter = Inter({ subsets: ['latin'] }). Font loading: system font until Google font downloads (approximately 1 second), no visual jump (CLS zero, font metric matching). next/script: Script tag with strategy property. afterInteractive loads after hydration complete (doesn't block rendering). beforeInteractive for Sentry, afterInteractive for GA, lazyOnload for help chat. Third-party scripts don't block page load (~100ms difference).

Middleware and Request/Response Processing

Middleware: runs before request reaches route handler. Example: /middleware.ts checks authentication: if (!jwt) redirect('/login'). Edge Functions (Cloudflare Workers, Vercel Edge): run within 50ms of user (edge location), redirect to login <100ms round-trip. Request headers inspection: headers().get('user-agent') detects device (mobile vs desktop). A/B testing: if (Math.random() > 0.5) rewrite('/variant-b') (server-side, user sees same URL). Cookies: cookies().set('theme', 'dark') persists across requests. Response headers: headers: { 'cache-control': 'max-age=3600' } caches for 1 hour. Streaming responses: Response to streaming data (video, large files) without buffering entire response in memory.

Data Fetching and Caching Strategy

fetch() with Next.js options: fetch(url, { cache: 'force-cache' }) caches indefinitely (static generation), cache: 'no-store' fetches on every request (dynamic). Revalidation: fetch(url, { next: { revalidate: 60 } }) caches for 60 seconds (ISR). Comparison to getStaticProps/getServerSideProps (Pages Router): App Router uses fetch() directly, Next.js detects caching behavior. Example: const data = await fetch(api, { next: { revalidate: 3600 } }), next.js automatically invalidates after 1 hour. Route handler caching: export const dynamic = 'force-dynamic' → never cache (like getServerSideProps). Client-side fetching: useEffect on client (old way), Server Components (new way, zero JavaScript). Mutation: Server Actions: <form action={async (formData) => { 'use server', await db.insert(formData) }}> → POST without API route.

Deployment and Edge Performance

Vercel deployment: push to GitHub → automatic preview (PR deployment <2 minutes), production (merged to main). Edge Middleware: runs on Vercel Edge Network (50+ global locations). Example: redirect UK users to /en-gb automatically (geolocation data available on edge). Analytics: Web Vitals (LCP, FID, CLS) auto-tracked. Optimization score: Web Vitals report highlights slow pages. Build output: next build → 2-3MB bundle typical (React 18 + Next.js + dependencies), production: gzipped ~500KB. Cold starts: Vercel <100ms (pre-warmed), AWS Lambda 1-3s (cold start penalty). Carbon emissions: Edge Functions reduce energy (process near user, 70% less data transfer). Hybrid rendering: static homepage (1ms), dynamic API routes (100-500ms), client components (interactive 50ms).