{"slug":"nextjs-app-router-architecture","title":"Next.js App Router Architecture: File Conventions and Layout Patterns","tags":["nextjs","app-router","server-components","ssr","full-stack"],"agent_summary":"Definitive reference for Next.js 14-16 App Router file conventions — layouts, loading states, error boundaries, route groups, parallel routes, and intercepting routes.","trigger_phrases":["Next.js App Router","layout.tsx","route groups","parallel routes","intercepting routes","Next.js file conventions"],"runnable":false,"markdown":"\n## Overview\n\nNext.js App Router uses a file-system routing model where specific filenames carry special meaning. Every route segment maps to a folder; every folder can have one or more of these special files.\n\n## Core File Conventions\n\n```\napp/\n  layout.tsx          # Root layout (wraps all pages, persists across navigations)\n  page.tsx            # Home route (/)\n  loading.tsx         # Loading UI (automatic Suspense boundary)\n  error.tsx           # Error boundary (\"use client\" required)\n  not-found.tsx       # 404 page\n  (marketing)/        # Route group — no URL segment\n    about/page.tsx    # /about\n    blog/page.tsx     # /blog\n  dashboard/\n    layout.tsx        # Nested layout (sidebar, chrome)\n    page.tsx          # /dashboard\n    settings/\n      page.tsx        # /dashboard/settings\n  api/\n    route.ts          # API route handler\n```\n\n**Layout rules:**\n- Root layout: HTML shell, global providers, fonts, analytics\n- Nested layouts: sidebar nav, dashboard chrome, section headers\n- Layouts receive `{children}` and persist across child navigations — no re-render on route change\n- Use `template.tsx` (not layout) when you need to re-mount on navigation (enter/exit animations)\n\n## Route Groups `(folder)`\n\nOrganize routes without affecting the URL path:\n\n```\napp/\n  (marketing)/\n    pricing/page.tsx    # /pricing\n    about/page.tsx      # /about\n  (app)/\n    dashboard/page.tsx  # /dashboard\n    profile/page.tsx    # /profile\n```\n\nBoth groups share the same root but can have **different layouts**. Use this to separate marketing pages (full-width) from app pages (with sidebar).\n\n## Parallel Routes `@folder`\n\nRender multiple pages simultaneously in the same layout:\n\n```\napp/\n  @modal/\n    login/page.tsx\n  @sidebar/\n    default.tsx         # Required: fallback when no active route\n  layout.tsx            # Receives { modal, sidebar, children }\n  page.tsx\n```\n\nUse for modals, split views, and dashboard panels that load independently.\n\n## Intercepting Routes `(.)folder`\n\nShow a modal on client navigation, full page on direct URL:\n\n```\napp/\n  photos/\n    [id]/page.tsx           # /photos/123 (full page, direct URL)\n  @modal/\n    (.)photos/[id]/page.tsx # Intercepts /photos/123 during navigation\n```\n\nThis is how Instagram-style photo modals work — click opens modal, direct URL or refresh shows full page.\n\n## Loading States\n\n```tsx\n// app/dashboard/loading.tsx\nexport default function Loading() {\n  return <DashboardSkeleton />;\n}\n```\n\nAutomatically wraps the page in a `<Suspense>` boundary. Shows while `page.tsx` data loads. Zero boilerplate.\n\n## Error Boundaries\n\n```tsx\n// app/dashboard/error.tsx — MUST be \"use client\"\n\"use client\";\nexport default function Error({ error, reset }: { error: Error; reset: () => void }) {\n  return (\n    <div>\n      <h2>Something went wrong</h2>\n      <button onClick={() => reset()}>Try again</button>\n    </div>\n  );\n}\n```\n\nCatches rendering errors in the segment and all children below it. Place at every major route level.\n\n## Turbopack (Next.js 16+)\n\nTurbopack is the **default** bundler in Next.js 16. No flags needed — `next dev` uses it automatically. Do NOT add `--turbopack` (deprecated). To opt out: `next dev --no-turbopack`.\n\nCache lives at `.next/cache/turbopack/` — add to `.gitignore`, cache in CI between runs.\n\n## Pre-Deploy Checklist\n\n- App Router structure follows conventions (layout, page, loading, error)\n- TypeScript strict mode enabled\n- Core Web Vitals > 90 (LCP < 2.5s, CLS < 0.1, INP < 200ms)\n- Error boundaries at every route segment\n- Deployment pipeline tested (preview + production)\n","html":"<h2>Overview</h2>\n<p>Next.js App Router uses a file-system routing model where specific filenames carry special meaning. Every route segment maps to a folder; every folder can have one or more of these special files.</p>\n<h2>Core File Conventions</h2>\n<pre><code>app/\n  layout.tsx          # Root layout (wraps all pages, persists across navigations)\n  page.tsx            # Home route (/)\n  loading.tsx         # Loading UI (automatic Suspense boundary)\n  error.tsx           # Error boundary (\"use client\" required)\n  not-found.tsx       # 404 page\n  (marketing)/        # Route group — no URL segment\n    about/page.tsx    # /about\n    blog/page.tsx     # /blog\n  dashboard/\n    layout.tsx        # Nested layout (sidebar, chrome)\n    page.tsx          # /dashboard\n    settings/\n      page.tsx        # /dashboard/settings\n  api/\n    route.ts          # API route handler\n</code></pre>\n<p><strong>Layout rules:</strong></p>\n<ul>\n<li>Root layout: HTML shell, global providers, fonts, analytics</li>\n<li>Nested layouts: sidebar nav, dashboard chrome, section headers</li>\n<li>Layouts receive <code>{children}</code> and persist across child navigations — no re-render on route change</li>\n<li>Use <code>template.tsx</code> (not layout) when you need to re-mount on navigation (enter/exit animations)</li>\n</ul>\n<h2>Route Groups <code>(folder)</code></h2>\n<p>Organize routes without affecting the URL path:</p>\n<pre><code>app/\n  (marketing)/\n    pricing/page.tsx    # /pricing\n    about/page.tsx      # /about\n  (app)/\n    dashboard/page.tsx  # /dashboard\n    profile/page.tsx    # /profile\n</code></pre>\n<p>Both groups share the same root but can have <strong>different layouts</strong>. Use this to separate marketing pages (full-width) from app pages (with sidebar).</p>\n<h2>Parallel Routes <code>@folder</code></h2>\n<p>Render multiple pages simultaneously in the same layout:</p>\n<pre><code>app/\n  @modal/\n    login/page.tsx\n  @sidebar/\n    default.tsx         # Required: fallback when no active route\n  layout.tsx            # Receives { modal, sidebar, children }\n  page.tsx\n</code></pre>\n<p>Use for modals, split views, and dashboard panels that load independently.</p>\n<h2>Intercepting Routes <code>(.)folder</code></h2>\n<p>Show a modal on client navigation, full page on direct URL:</p>\n<pre><code>app/\n  photos/\n    [id]/page.tsx           # /photos/123 (full page, direct URL)\n  @modal/\n    (.)photos/[id]/page.tsx # Intercepts /photos/123 during navigation\n</code></pre>\n<p>This is how Instagram-style photo modals work — click opens modal, direct URL or refresh shows full page.</p>\n<h2>Loading States</h2>\n<pre><code class=\"language-tsx\">// app/dashboard/loading.tsx\nexport default function Loading() {\n  return &#x3C;DashboardSkeleton />;\n}\n</code></pre>\n<p>Automatically wraps the page in a <code>&#x3C;Suspense></code> boundary. Shows while <code>page.tsx</code> data loads. Zero boilerplate.</p>\n<h2>Error Boundaries</h2>\n<pre><code class=\"language-tsx\">// app/dashboard/error.tsx — MUST be \"use client\"\n\"use client\";\nexport default function Error({ error, reset }: { error: Error; reset: () => void }) {\n  return (\n    &#x3C;div>\n      &#x3C;h2>Something went wrong&#x3C;/h2>\n      &#x3C;button onClick={() => reset()}>Try again&#x3C;/button>\n    &#x3C;/div>\n  );\n}\n</code></pre>\n<p>Catches rendering errors in the segment and all children below it. Place at every major route level.</p>\n<h2>Turbopack (Next.js 16+)</h2>\n<p>Turbopack is the <strong>default</strong> bundler in Next.js 16. No flags needed — <code>next dev</code> uses it automatically. Do NOT add <code>--turbopack</code> (deprecated). To opt out: <code>next dev --no-turbopack</code>.</p>\n<p>Cache lives at <code>.next/cache/turbopack/</code> — add to <code>.gitignore</code>, cache in CI between runs.</p>\n<h2>Pre-Deploy Checklist</h2>\n<ul>\n<li>App Router structure follows conventions (layout, page, loading, error)</li>\n<li>TypeScript strict mode enabled</li>\n<li>Core Web Vitals > 90 (LCP &#x3C; 2.5s, CLS &#x3C; 0.1, INP &#x3C; 200ms)</li>\n<li>Error boundaries at every route segment</li>\n<li>Deployment pipeline tested (preview + production)</li>\n</ul>\n"}