nextjs_advanced 30 Q&As

Next.js Advanced FAQ & Answers

30 expert Next.js Advanced answers researched from official documentation. Every answer cites authoritative sources you can verify.

unknown

30 questions
A

App Router reduces client JavaScript by 20-30% through React Server Components (RSC) as default rendering model. Architecture: Server components render on server without shipping code to client. App directory: server components default, client components require 'use client' directive. Performance benefits: (1) Zero hydration cost - server components are HTML with no client JavaScript, no hydration needed. (2) Automatic code splitting - only client components bundle to browser. (3) Streaming HTML - progressive rendering via Suspense. Comparison: Pages Router SSR sends HTML + full page JavaScript (all components hydrate). App Router sends HTML + only interactive component JavaScript (server components stay HTML). Real-world: E-commerce site reduced bundle 450KB → 180KB by moving product display to server components, keeping only cart/checkout as client components. Component selection: Server components for: data fetching (database queries, API calls), layouts (navigation, headers), static content (markdown, product descriptions). Client components for: interactivity (onClick, useState, useEffect), browser APIs (window, localStorage), third-party widgets requiring client.

99% confidence
A

App Router advantages: (1) Smaller bundles - 20-30% reduction via Server Components. (2) Better TTI - only interactive components hydrate. (3) Streaming - progressive rendering improves perceived performance. (4) Future-proof - designed for React Server Components, official Next.js recommendation. (5) 76% faster local dev - Turbopack Dev (stable in Next.js 15). Pages Router advantages: (1) Higher throughput - handles 6× more concurrent requests in heavy SSR scenarios. (2) Simpler mental model - all components work same way, no server/client split. (3) Mature ecosystem - more third-party libraries compatible. Infrastructure costs: App Router can increase serverless costs and cold start times due to server-side rendering overhead. Mitigation: strategic caching (ISR, cache tags), rendering boundaries (minimize dynamic rendering). When to choose: App Router for: SEO-heavy apps, performance-focused content sites, new projects. Pages Router for: existing apps, high-traffic APIs requiring maximum throughput, teams unfamiliar with RSC. Migration: Gradual - run both routers simultaneously, move routes incrementally from pages/ to app/.

99% confidence
A

Parallel routes render multiple pages simultaneously in same layout, each in named 'slot'. Syntax: Create folders with @ prefix: @analytics, @team, @dashboard. Layout receives slots as props: export default function Layout({ children, analytics, team, dashboard }) { return <><div>{children}</div><aside>{analytics}</aside><div>{team}</div><div>{dashboard}</div></> }. Use cases: (1) Dashboards - independent data sections (analytics panel + team roster + metrics), each slot fetches own data in parallel. (2) Admin panels - sidebar + main content + notifications as separate slots. (3) A/B testing - render different layouts simultaneously. Benefits: (1) Each slot has own loading.js and error.js - independent Suspense boundaries, one section loading doesn't block others. (2) Parallel data fetching - all slots fetch simultaneously, not sequentially. (3) Independent error handling - one slot error doesn't crash entire page. Performance: 40-60% faster Time to Interactive vs sequential loading. Example: Dashboard with @analytics (5s data load), @team (1s load), @metrics (3s load) - all load in parallel, page interactive when first slot ready. Layout: app/dashboard/layout.tsx, slots: app/dashboard/@analytics/page.tsx, app/dashboard/@team/page.tsx. Next.js 13+ feature.

99% confidence
A

Intercepting routes show one route while navigating to another - typically for modals that maintain URL state. Syntax: (.) same level, (..) one up, (..)(..) two up, (...) root. Pattern: Photo gallery with modal. Structure: app/photos/page.tsx (gallery grid), app/@modal/(.)photos/[id]/page.tsx (photo modal), app/photos/[id]/page.tsx (full photo page). Behavior: Clicking photo from gallery → shows modal over gallery (intercepting route), URL updates to /photos/123. Direct navigation /photos/123 or refresh → loads full photo page. Back button → closes modal, returns to gallery. Benefits: (1) URL updates - shareable links work (send /photos/123 to friend). (2) Intuitive navigation - back button closes modal naturally. (3) Refresh loads correct view - direct access shows dedicated page. Implementation: app/@modal/(.)photos/[id]/page.tsx: export default function PhotoModal({ params }) { return <Modal><Image src={getPhoto(params.id)} /></Modal> }. Combine with parallel routes: modal in @modal slot, main content in children. Real-world: Twitter-like photo viewer, product quick view in e-commerce, user profile modals. Advanced: Multiple intercepting levels for nested modals. Next.js 13+ feature.

99% confidence
A

Next.js 15 fetch() is cache-aware by default with automatic optimization. Caching strategies: (1) Static (default): fetch(url) caches indefinitely, reused across requests, persists across deployments (shared CDN cache). Perfect for stable data (product catalogs, markdown content). (2) Revalidate (ISR): fetch(url, { next: { revalidate: 60 } }) caches then revalidates after 60 seconds. First request caches, subsequent requests serve cache, after 60s background revalidation triggers, next request gets fresh data. Best for: frequently updated data (news, prices). (3) Dynamic (no cache): fetch(url, { cache: 'no-store' }) never caches, fetches on every request. Use for: user-specific data, real-time info, personalized content. Route-level defaults: export const revalidate = 60 sets default for all fetches in route. export const dynamic = 'force-static' forces static. export const dynamic = 'force-dynamic' forces dynamic. Deduplication: Automatic within same render pass - multiple components fetching same URL execute request once, share result. Performance: Static/ISR serve from CDN (10-50ms), dynamic requires server round-trip (100-500ms).

99% confidence
A

Cache tags enable granular cache invalidation without revalidating entire routes. Tagging data: fetch(url, { next: { tags: ['products'] } }) tags fetch with identifier. Invalidation: Use Server Action or API Route: import { revalidateTag } from 'next/cache'; revalidateTag('products');. All fetches tagged 'products' invalidate immediately, trigger revalidation on next request. Hierarchical tagging: Tag at multiple levels for granular control: fetch(url, { next: { tags: ['products', 'product-123', 'category-electronics'] } }). Invalidate entire category: revalidateTag('category-electronics'). Invalidate single product: revalidateTag('product-123'). Use cases: (1) E-commerce - product update invalidates product page + category + search results via multiple tags. (2) Blog - new post invalidates homepage, category, author page via tags. (3) User data - profile update invalidates user-specific pages only via user ID tag. Route invalidation: import { revalidatePath } from 'next/cache'; revalidatePath('/products'); invalidates entire route. Performance: Targeted invalidation = efficient caching, only affected pages revalidate. Cache persistence: Tags persist across deployments, provide consistent invalidation. Best practice: Tag hierarchically, invalidate minimally (only what changed).

99% confidence
A

Server Actions are async functions marked 'use server' that execute on server, callable from client/server components. Stable in Next.js 15 (October 2024). Basic implementation: async function createTodo(formData: FormData) { 'use server'; const text = formData.get('text') as string; await db.todos.create({ text }); revalidatePath('/todos'); }. Form integration: <form action={createTodo}><input name="text" /><button>Add</button></form>. Progressive enhancement: Forms work without JavaScript - standard form POST to unguessable endpoint, Next.js handles automatically. With arguments: Use bind() to pass additional parameters: <form action={deleteTodo.bind(null, todoId)}>. In components: Call directly: const result = await createUser(formData). Return values: Serializable only (no functions, classes): return { success: true, userId: '123' }. Security: Runs with server permissions, validate ALL inputs (never trust client data): if (!text || text.length > 100) throw new Error('Invalid'). Apply rate limiting to prevent abuse. Error handling: Use try-catch, return error objects: try { await save(); return { success: true }; } catch (e) { return { success: false, error: e.message }; }.

99% confidence
A

Server Actions advantages: (1) No manual endpoints - no need to create /api/users/create.ts route file. Function becomes endpoint automatically with unguessable URL. (2) End-to-end type safety - TypeScript types flow from server to client, full autocomplete. API route requires separate type definitions for request/response. (3) Smaller bundles - no fetch code on client (fetch('/api/create', { method: 'POST', body: JSON.stringify(data) }) eliminated). Saves 5-10KB per action. (4) Progressive enhancement - forms work without JavaScript. Graceful degradation for poor connections. (5) Automatic serialization - FormData handling built-in, no manual JSON.stringify/parse. (6) Better DX - colocate with components, no separate API folder structure. React hooks integration: useFormStatus() for pending states (disable submit button automatically). useFormState() for optimistic updates and error handling. Performance: Reduces client bundle, streams responses with Suspense. When to use API routes instead: (1) Third-party webhooks requiring stable URLs. (2) GET requests (Server Actions are POST-only). (3) Public APIs for external consumption. Best practice: Server Actions for internal mutations, API routes for external/webhook integrations.

99% confidence
A

Streaming progressively sends HTML to browser as server generates it, reducing Time to First Byte (TTFB) and enabling faster interaction. Implementation: Wrap slow components in Suspense: <Suspense fallback={<ProductSkeleton />}><Products /></Suspense>. Server behavior: (1) Immediately sends static shell (layout, navigation, Suspense fallback). (2) Streams dynamic content as it resolves. (3) Browser receives: <div>Loading...</div> → later replaced with <div>Product list...</div> when data loads. Automatic streaming: loading.js creates Suspense boundary for entire route segment. Performance benefits: (1) 40-60% faster TTI - users interact before full page loads. (2) Parallel data fetching - multiple Suspense boundaries load simultaneously, not sequentially. (3) Improved LCP - Largest Contentful Paint improves 30-50% on slow connections as critical content streams first. Requirements: Streaming-compatible server (Node.js 14+, Edge Runtime supported). Doesn't work with output: 'export' (static export). Combine with: React.lazy() for code splitting, Server Components for minimal client JavaScript. Real-world: Dashboard with 3 widgets (5s, 2s, 8s load times) - streams shell instantly, widgets appear as ready. User interacts with shell while widgets load.

99% confidence
A

Partial hydration selectively hydrates only interactive components, leaving server components as static HTML. Mechanism: Server components render to HTML on server, never hydrate on client (no JavaScript shipped). Client components (marked 'use client') hydrate normally. Performance: (1) Reduced JavaScript execution - only necessary components hydrate, not entire page. Server component tree stays inert HTML. (2) Faster TTI - less hydration work = users interact sooner. 40-60% improvement in JavaScript-heavy apps. (3) Lower memory usage - fewer React component instances in browser memory. Example: Product page with server component (product details, reviews - static HTML) + client component ("Add to Cart" button - hydrates with onClick). Only cart button executes JavaScript, product data stays HTML. Architecture: Server component tree can include client components as children: server components render to HTML, client component markers stream with shell, client components hydrate when streamed. Optimization: Minimize client components - only mark interactive parts with 'use client'. Large static sections (layouts, content, images) benefit most as server components. Measurement: Check bundle size with @next/bundle-analyzer - server components have zero client JavaScript. Target: <30% of components need client interactivity.

99% confidence
A

Route Groups organize routes without affecting URL structure using parentheses: (folderName). URL impact: Parentheses excluded from URLs. app/(marketing)/about/page.tsx renders at /about, not /(marketing)/about. Use cases: (1) Organization: app/(marketing)/about and app/(shop)/products group related routes logically while rendering at /about and /products. (2) Shared layouts: app/(dashboard)/layout.tsx applies to app/(dashboard)/analytics and app/(dashboard)/settings - both share dashboard layout. (3) Multiple root layouts: app/(marketing)/layout.tsx and app/(shop)/layout.tsx enable different HTML structures (different , fonts, headers). Useful for distinct sections requiring separate designs. Benefits: (1) Cleaner file structure - group related routes by feature, team, or user type. (2) Reusable layouts - avoid duplication across similar routes. (3) Multiple root layouts in one project - serve different apps/experiences. Example structure: app/(auth)/(modal)/@authModal/(.)login/page.tsx - auth group with modal slot and intercepted login route (combines Route Groups + Parallel Routes + Intercepting Routes). Convention: Use descriptive names ((marketing), (admin), (public)), lowercase with hyphens. Next.js 13+ feature.

99% confidence
A

Next.js App Router automatically code splits by route segment - each folder creates separate chunk. Manual optimization with next/dynamic: const HeavyChart = dynamic(() => import('./Chart'), { loading: () => <Skeleton />, ssr: false }). Creates separate chunk loaded only when component renders. Options: ssr: false prevents server-side execution (browser-only components like charts, maps), loading shows placeholder during chunk download. Conditional loading: Load based on interaction: const Editor = dynamic(() => import('./Editor')); const [show, setShow] = useState(false); {show && <Editor />} - editor chunk loads only when show true. Library splitting: Defer heavy dependencies: const loadChart = async () => { const { Chart } = await import('react-chartjs-2'); setChart(Chart); };. Call in useEffect or onClick. Named exports: dynamic(() => import('./components').then(mod => mod.SpecificComponent)). Performance: Dynamic import with ssr: false reduces server bundle 20-40% for browser-only code. Combine with Suspense: <Suspense fallback={<Loading />}><LazyComponent /></Suspense>. Measurement: Use @next/bundle-analyzer to visualize chunks. Target: Main bundle <200KB, lazy-load components >50KB. Gotcha: Too many chunks increase HTTP requests - bundle related components together.

99% confidence
A

force-static: Pre-renders at build time, serves cached HTML. Configure: export const dynamic = 'force-static'. Behavior: fetch() caches by default, page generated once at build, served from CDN. Use for: Marketing pages, blogs, documentation, product catalogs - content that doesn't change per request. Benefits: Fastest performance (10-50ms from CDN), no runtime computation, works offline, scales infinitely (static files). force-dynamic: Renders on every request, no caching. Configure: export const dynamic = 'force-dynamic' or use cookies()/headers() (automatically switches to dynamic). Behavior: fetch() doesn't cache unless explicit cache option, page generated per request. Use for: Personalized dashboards, real-time data, user-specific content ("Welcome, John"), admin panels requiring fresh data. Trade-off: force-dynamic is 5-10× slower (100-500ms vs 10-50ms) but always fresh. Automatic detection: Using request-time APIs (cookies(), headers(), searchParams) makes route dynamic automatically. Hybrid approach: Static layout + dynamic nested component: layout stays force-static (fast shell), nested component force-dynamic (fresh data). Best practice: Default to force-static with ISR (revalidate: 60), use force-dynamic only for truly per-request data.

99% confidence
A

next/image component provides automatic optimization: responsive sizing, lazy loading, modern formats (WebP, AVIF). Key props: (1) fill mode for responsive images: <Image src="..." fill sizes="(max-width: 768px) 100vw, 50vw" />. sizes determines rendered width at breakpoints - critical for correct image download size. (2) priority for above-fold images disables lazy loading, preloads for faster LCP: <Image src="hero.jpg" priority />. (3) quality (1-100, default 75) balances size vs clarity. Remote images: Configure in next.config.js: images: { remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }] }. Custom loader for CDN: loader: ({ src, width, quality }) => https://cdn.com/${src}?w=${width}&q=${quality || 75}`` integrates Cloudinary, Imgix, Cloudflare Images. Placeholder blur: placeholder="blur" blurDataURL="data:image/..." shows low-res preview during load (improves perceived performance, reduces layout shift). Performance: Reduces LCP by 40-60%. Automatic: format selection (WebP on supported browsers, fallback), responsive srcset generation, lazy loading below fold. Best practices: Use fill for flexible layouts, define accurate sizes (prevents downloading 2000px image for 500px display), serve from CDN, use priority for hero images. Avoid: Image in map() without memoization, using Image for icons <40px (use SVG).

99% confidence
A

layout.js: Mounts once, persists across navigations, state preserved. template.js: Creates new instance on every navigation, remounts, state resets. Use layout.js for: (1) Shared UI persisting across routes (navigation, sidebar, header). (2) Expensive components to mount once (complex state, WebSocket connections). (3) State preservation (search filters, scroll position, form inputs). Use template.js for: (1) Components requiring reset on navigation (modals, forms should clear). (2) Entry/exit animations needing remount (className="fade-in" triggers on each page). (3) Analytics tracking - useEffect(() => trackPageView()) fires on every navigation. Performance: Templates slightly slower (remounting cost), use sparingly. Example: Analytics tracking - export default function Template({ children }) { useEffect(() => { analytics.page(); }, []); return <div className="fade-in">{children}</div>; } - fires pageview and animation on each route change. Layout for persistent search: export default function Layout({ children }) { const [search, setSearch] = useState(''); return <><SearchBar value={search} onChange={setSearch} />{children}</>; } - search state persists between pages. Nesting: Both wrap children, template.js nests inside layout.js: Layout → Template → Page. Recommendation: Default to layout.js, use template.js only when reset behavior required. Next.js 13+ feature.

99% confidence
A

App Router reduces client JavaScript by 20-30% through React Server Components (RSC) as default rendering model. Architecture: Server components render on server without shipping code to client. App directory: server components default, client components require 'use client' directive. Performance benefits: (1) Zero hydration cost - server components are HTML with no client JavaScript, no hydration needed. (2) Automatic code splitting - only client components bundle to browser. (3) Streaming HTML - progressive rendering via Suspense. Comparison: Pages Router SSR sends HTML + full page JavaScript (all components hydrate). App Router sends HTML + only interactive component JavaScript (server components stay HTML). Real-world: E-commerce site reduced bundle 450KB → 180KB by moving product display to server components, keeping only cart/checkout as client components. Component selection: Server components for: data fetching (database queries, API calls), layouts (navigation, headers), static content (markdown, product descriptions). Client components for: interactivity (onClick, useState, useEffect), browser APIs (window, localStorage), third-party widgets requiring client.

99% confidence
A

App Router advantages: (1) Smaller bundles - 20-30% reduction via Server Components. (2) Better TTI - only interactive components hydrate. (3) Streaming - progressive rendering improves perceived performance. (4) Future-proof - designed for React Server Components, official Next.js recommendation. (5) 76% faster local dev - Turbopack Dev (stable in Next.js 15). Pages Router advantages: (1) Higher throughput - handles 6× more concurrent requests in heavy SSR scenarios. (2) Simpler mental model - all components work same way, no server/client split. (3) Mature ecosystem - more third-party libraries compatible. Infrastructure costs: App Router can increase serverless costs and cold start times due to server-side rendering overhead. Mitigation: strategic caching (ISR, cache tags), rendering boundaries (minimize dynamic rendering). When to choose: App Router for: SEO-heavy apps, performance-focused content sites, new projects. Pages Router for: existing apps, high-traffic APIs requiring maximum throughput, teams unfamiliar with RSC. Migration: Gradual - run both routers simultaneously, move routes incrementally from pages/ to app/.

99% confidence
A

Parallel routes render multiple pages simultaneously in same layout, each in named 'slot'. Syntax: Create folders with @ prefix: @analytics, @team, @dashboard. Layout receives slots as props: export default function Layout({ children, analytics, team, dashboard }) { return <><div>{children}</div><aside>{analytics}</aside><div>{team}</div><div>{dashboard}</div></> }. Use cases: (1) Dashboards - independent data sections (analytics panel + team roster + metrics), each slot fetches own data in parallel. (2) Admin panels - sidebar + main content + notifications as separate slots. (3) A/B testing - render different layouts simultaneously. Benefits: (1) Each slot has own loading.js and error.js - independent Suspense boundaries, one section loading doesn't block others. (2) Parallel data fetching - all slots fetch simultaneously, not sequentially. (3) Independent error handling - one slot error doesn't crash entire page. Performance: 40-60% faster Time to Interactive vs sequential loading. Example: Dashboard with @analytics (5s data load), @team (1s load), @metrics (3s load) - all load in parallel, page interactive when first slot ready. Layout: app/dashboard/layout.tsx, slots: app/dashboard/@analytics/page.tsx, app/dashboard/@team/page.tsx. Next.js 13+ feature.

99% confidence
A

Intercepting routes show one route while navigating to another - typically for modals that maintain URL state. Syntax: (.) same level, (..) one up, (..)(..) two up, (...) root. Pattern: Photo gallery with modal. Structure: app/photos/page.tsx (gallery grid), app/@modal/(.)photos/[id]/page.tsx (photo modal), app/photos/[id]/page.tsx (full photo page). Behavior: Clicking photo from gallery → shows modal over gallery (intercepting route), URL updates to /photos/123. Direct navigation /photos/123 or refresh → loads full photo page. Back button → closes modal, returns to gallery. Benefits: (1) URL updates - shareable links work (send /photos/123 to friend). (2) Intuitive navigation - back button closes modal naturally. (3) Refresh loads correct view - direct access shows dedicated page. Implementation: app/@modal/(.)photos/[id]/page.tsx: export default function PhotoModal({ params }) { return <Modal><Image src={getPhoto(params.id)} /></Modal> }. Combine with parallel routes: modal in @modal slot, main content in children. Real-world: Twitter-like photo viewer, product quick view in e-commerce, user profile modals. Advanced: Multiple intercepting levels for nested modals. Next.js 13+ feature.

99% confidence
A

Next.js 15 fetch() is cache-aware by default with automatic optimization. Caching strategies: (1) Static (default): fetch(url) caches indefinitely, reused across requests, persists across deployments (shared CDN cache). Perfect for stable data (product catalogs, markdown content). (2) Revalidate (ISR): fetch(url, { next: { revalidate: 60 } }) caches then revalidates after 60 seconds. First request caches, subsequent requests serve cache, after 60s background revalidation triggers, next request gets fresh data. Best for: frequently updated data (news, prices). (3) Dynamic (no cache): fetch(url, { cache: 'no-store' }) never caches, fetches on every request. Use for: user-specific data, real-time info, personalized content. Route-level defaults: export const revalidate = 60 sets default for all fetches in route. export const dynamic = 'force-static' forces static. export const dynamic = 'force-dynamic' forces dynamic. Deduplication: Automatic within same render pass - multiple components fetching same URL execute request once, share result. Performance: Static/ISR serve from CDN (10-50ms), dynamic requires server round-trip (100-500ms).

99% confidence
A

Cache tags enable granular cache invalidation without revalidating entire routes. Tagging data: fetch(url, { next: { tags: ['products'] } }) tags fetch with identifier. Invalidation: Use Server Action or API Route: import { revalidateTag } from 'next/cache'; revalidateTag('products');. All fetches tagged 'products' invalidate immediately, trigger revalidation on next request. Hierarchical tagging: Tag at multiple levels for granular control: fetch(url, { next: { tags: ['products', 'product-123', 'category-electronics'] } }). Invalidate entire category: revalidateTag('category-electronics'). Invalidate single product: revalidateTag('product-123'). Use cases: (1) E-commerce - product update invalidates product page + category + search results via multiple tags. (2) Blog - new post invalidates homepage, category, author page via tags. (3) User data - profile update invalidates user-specific pages only via user ID tag. Route invalidation: import { revalidatePath } from 'next/cache'; revalidatePath('/products'); invalidates entire route. Performance: Targeted invalidation = efficient caching, only affected pages revalidate. Cache persistence: Tags persist across deployments, provide consistent invalidation. Best practice: Tag hierarchically, invalidate minimally (only what changed).

99% confidence
A

Server Actions are async functions marked 'use server' that execute on server, callable from client/server components. Stable in Next.js 15 (October 2024). Basic implementation: async function createTodo(formData: FormData) { 'use server'; const text = formData.get('text') as string; await db.todos.create({ text }); revalidatePath('/todos'); }. Form integration: <form action={createTodo}><input name="text" /><button>Add</button></form>. Progressive enhancement: Forms work without JavaScript - standard form POST to unguessable endpoint, Next.js handles automatically. With arguments: Use bind() to pass additional parameters: <form action={deleteTodo.bind(null, todoId)}>. In components: Call directly: const result = await createUser(formData). Return values: Serializable only (no functions, classes): return { success: true, userId: '123' }. Security: Runs with server permissions, validate ALL inputs (never trust client data): if (!text || text.length > 100) throw new Error('Invalid'). Apply rate limiting to prevent abuse. Error handling: Use try-catch, return error objects: try { await save(); return { success: true }; } catch (e) { return { success: false, error: e.message }; }.

99% confidence
A

Server Actions advantages: (1) No manual endpoints - no need to create /api/users/create.ts route file. Function becomes endpoint automatically with unguessable URL. (2) End-to-end type safety - TypeScript types flow from server to client, full autocomplete. API route requires separate type definitions for request/response. (3) Smaller bundles - no fetch code on client (fetch('/api/create', { method: 'POST', body: JSON.stringify(data) }) eliminated). Saves 5-10KB per action. (4) Progressive enhancement - forms work without JavaScript. Graceful degradation for poor connections. (5) Automatic serialization - FormData handling built-in, no manual JSON.stringify/parse. (6) Better DX - colocate with components, no separate API folder structure. React hooks integration: useFormStatus() for pending states (disable submit button automatically). useFormState() for optimistic updates and error handling. Performance: Reduces client bundle, streams responses with Suspense. When to use API routes instead: (1) Third-party webhooks requiring stable URLs. (2) GET requests (Server Actions are POST-only). (3) Public APIs for external consumption. Best practice: Server Actions for internal mutations, API routes for external/webhook integrations.

99% confidence
A

Streaming progressively sends HTML to browser as server generates it, reducing Time to First Byte (TTFB) and enabling faster interaction. Implementation: Wrap slow components in Suspense: <Suspense fallback={<ProductSkeleton />}><Products /></Suspense>. Server behavior: (1) Immediately sends static shell (layout, navigation, Suspense fallback). (2) Streams dynamic content as it resolves. (3) Browser receives: <div>Loading...</div> → later replaced with <div>Product list...</div> when data loads. Automatic streaming: loading.js creates Suspense boundary for entire route segment. Performance benefits: (1) 40-60% faster TTI - users interact before full page loads. (2) Parallel data fetching - multiple Suspense boundaries load simultaneously, not sequentially. (3) Improved LCP - Largest Contentful Paint improves 30-50% on slow connections as critical content streams first. Requirements: Streaming-compatible server (Node.js 14+, Edge Runtime supported). Doesn't work with output: 'export' (static export). Combine with: React.lazy() for code splitting, Server Components for minimal client JavaScript. Real-world: Dashboard with 3 widgets (5s, 2s, 8s load times) - streams shell instantly, widgets appear as ready. User interacts with shell while widgets load.

99% confidence
A

Partial hydration selectively hydrates only interactive components, leaving server components as static HTML. Mechanism: Server components render to HTML on server, never hydrate on client (no JavaScript shipped). Client components (marked 'use client') hydrate normally. Performance: (1) Reduced JavaScript execution - only necessary components hydrate, not entire page. Server component tree stays inert HTML. (2) Faster TTI - less hydration work = users interact sooner. 40-60% improvement in JavaScript-heavy apps. (3) Lower memory usage - fewer React component instances in browser memory. Example: Product page with server component (product details, reviews - static HTML) + client component ("Add to Cart" button - hydrates with onClick). Only cart button executes JavaScript, product data stays HTML. Architecture: Server component tree can include client components as children: server components render to HTML, client component markers stream with shell, client components hydrate when streamed. Optimization: Minimize client components - only mark interactive parts with 'use client'. Large static sections (layouts, content, images) benefit most as server components. Measurement: Check bundle size with @next/bundle-analyzer - server components have zero client JavaScript. Target: <30% of components need client interactivity.

99% confidence
A

Route Groups organize routes without affecting URL structure using parentheses: (folderName). URL impact: Parentheses excluded from URLs. app/(marketing)/about/page.tsx renders at /about, not /(marketing)/about. Use cases: (1) Organization: app/(marketing)/about and app/(shop)/products group related routes logically while rendering at /about and /products. (2) Shared layouts: app/(dashboard)/layout.tsx applies to app/(dashboard)/analytics and app/(dashboard)/settings - both share dashboard layout. (3) Multiple root layouts: app/(marketing)/layout.tsx and app/(shop)/layout.tsx enable different HTML structures (different , fonts, headers). Useful for distinct sections requiring separate designs. Benefits: (1) Cleaner file structure - group related routes by feature, team, or user type. (2) Reusable layouts - avoid duplication across similar routes. (3) Multiple root layouts in one project - serve different apps/experiences. Example structure: app/(auth)/(modal)/@authModal/(.)login/page.tsx - auth group with modal slot and intercepted login route (combines Route Groups + Parallel Routes + Intercepting Routes). Convention: Use descriptive names ((marketing), (admin), (public)), lowercase with hyphens. Next.js 13+ feature.

99% confidence
A

Next.js App Router automatically code splits by route segment - each folder creates separate chunk. Manual optimization with next/dynamic: const HeavyChart = dynamic(() => import('./Chart'), { loading: () => <Skeleton />, ssr: false }). Creates separate chunk loaded only when component renders. Options: ssr: false prevents server-side execution (browser-only components like charts, maps), loading shows placeholder during chunk download. Conditional loading: Load based on interaction: const Editor = dynamic(() => import('./Editor')); const [show, setShow] = useState(false); {show && <Editor />} - editor chunk loads only when show true. Library splitting: Defer heavy dependencies: const loadChart = async () => { const { Chart } = await import('react-chartjs-2'); setChart(Chart); };. Call in useEffect or onClick. Named exports: dynamic(() => import('./components').then(mod => mod.SpecificComponent)). Performance: Dynamic import with ssr: false reduces server bundle 20-40% for browser-only code. Combine with Suspense: <Suspense fallback={<Loading />}><LazyComponent /></Suspense>. Measurement: Use @next/bundle-analyzer to visualize chunks. Target: Main bundle <200KB, lazy-load components >50KB. Gotcha: Too many chunks increase HTTP requests - bundle related components together.

99% confidence
A

force-static: Pre-renders at build time, serves cached HTML. Configure: export const dynamic = 'force-static'. Behavior: fetch() caches by default, page generated once at build, served from CDN. Use for: Marketing pages, blogs, documentation, product catalogs - content that doesn't change per request. Benefits: Fastest performance (10-50ms from CDN), no runtime computation, works offline, scales infinitely (static files). force-dynamic: Renders on every request, no caching. Configure: export const dynamic = 'force-dynamic' or use cookies()/headers() (automatically switches to dynamic). Behavior: fetch() doesn't cache unless explicit cache option, page generated per request. Use for: Personalized dashboards, real-time data, user-specific content ("Welcome, John"), admin panels requiring fresh data. Trade-off: force-dynamic is 5-10× slower (100-500ms vs 10-50ms) but always fresh. Automatic detection: Using request-time APIs (cookies(), headers(), searchParams) makes route dynamic automatically. Hybrid approach: Static layout + dynamic nested component: layout stays force-static (fast shell), nested component force-dynamic (fresh data). Best practice: Default to force-static with ISR (revalidate: 60), use force-dynamic only for truly per-request data.

99% confidence
A

next/image component provides automatic optimization: responsive sizing, lazy loading, modern formats (WebP, AVIF). Key props: (1) fill mode for responsive images: <Image src="..." fill sizes="(max-width: 768px) 100vw, 50vw" />. sizes determines rendered width at breakpoints - critical for correct image download size. (2) priority for above-fold images disables lazy loading, preloads for faster LCP: <Image src="hero.jpg" priority />. (3) quality (1-100, default 75) balances size vs clarity. Remote images: Configure in next.config.js: images: { remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }] }. Custom loader for CDN: loader: ({ src, width, quality }) => https://cdn.com/${src}?w=${width}&q=${quality || 75}`` integrates Cloudinary, Imgix, Cloudflare Images. Placeholder blur: placeholder="blur" blurDataURL="data:image/..." shows low-res preview during load (improves perceived performance, reduces layout shift). Performance: Reduces LCP by 40-60%. Automatic: format selection (WebP on supported browsers, fallback), responsive srcset generation, lazy loading below fold. Best practices: Use fill for flexible layouts, define accurate sizes (prevents downloading 2000px image for 500px display), serve from CDN, use priority for hero images. Avoid: Image in map() without memoization, using Image for icons <40px (use SVG).

99% confidence
A

layout.js: Mounts once, persists across navigations, state preserved. template.js: Creates new instance on every navigation, remounts, state resets. Use layout.js for: (1) Shared UI persisting across routes (navigation, sidebar, header). (2) Expensive components to mount once (complex state, WebSocket connections). (3) State preservation (search filters, scroll position, form inputs). Use template.js for: (1) Components requiring reset on navigation (modals, forms should clear). (2) Entry/exit animations needing remount (className="fade-in" triggers on each page). (3) Analytics tracking - useEffect(() => trackPageView()) fires on every navigation. Performance: Templates slightly slower (remounting cost), use sparingly. Example: Analytics tracking - export default function Template({ children }) { useEffect(() => { analytics.page(); }, []); return <div className="fade-in">{children}</div>; } - fires pageview and animation on each route change. Layout for persistent search: export default function Layout({ children }) { const [search, setSearch] = useState(''); return <><SearchBar value={search} onChange={setSearch} />{children}</>; } - search state persists between pages. Nesting: Both wrap children, template.js nests inside layout.js: Layout → Template → Page. Recommendation: Default to layout.js, use template.js only when reset behavior required. Next.js 13+ feature.

99% confidence