Technology · Next.js

Next.js App Router

Master file-based routing with the App Router for modern Next.js apps.

TL;DR
  1. 01Create routes by organizing files in the app folder structure.
  2. 02Each page.tsx or page.jsx file becomes a route automatically.
  3. 03Use brackets [param] for dynamic routes like /blog/[slug].

Basic Routing

  • Create pages by adding folders and page.tsx files.
    app/
      page.tsx              # / route
      about/page.tsx        # /about route
      blog/page.tsx         # /blog route
  • Each folder represents a path segment in the URL.
  • Rename page.tsx files to match your naming convention.
  • Export a default React component from each page file.
    // app/about/page.tsx
    export default function About() {
      return <h1>About Us</h1>;
    }
  • Use async functions in pages to fetch data on the server.
    // app/blog/page.tsx
    export default async function Blog() {
      const posts = await getPosts();
      return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
    }

Dynamic Routes

  • Create dynamic routes with bracket syntax [param].
    app/
      blog/
        [slug]/
          page.tsx          # /blog/:slug route
  • Access dynamic parameters in components.
    export default function BlogPost({ params }) {
      return <h1>Post: {params.slug}</h1>;
    }
  • Use multiple dynamic segments for nested routes.
    app/
      users/[id]/posts/[postId]/page.tsx
      # /users/:id/posts/:postId
  • Generate static pages from dynamic params with generateStaticParams.
    export async function generateStaticParams() {
      const posts = await getPosts();
      return posts.map(p => ({ slug: p.slug }));
    }
  • Use notFound() to return a 404 when a resource is missing.
    import { notFound } from "next/navigation";
    
    export default async function Post({ params }) {
      const post = await getPost(params.slug);
      if (!post) notFound();
      return <article>{post.content}</article>;
    }

Layouts

  • Create shared layouts with layout.tsx files.
    // app/layout.tsx
    export default function RootLayout({ children }) {
      return (
        <html>
          <body>
            <Header />
            {children}
            <Footer />
          </body>
        </html>
      );
    }
  • Each folder can have its own layout.
    // app/blog/layout.tsx
    export default function BlogLayout({ children }) {
      return (
        <div>
          <Sidebar />
          {children}
        </div>
      );
    }
  • Nested layouts wrap their children.
  • Root layout must include html and body tags.
    // app/layout.tsx — required at the root
    export default function RootLayout({ children }) {
      return (
        <html lang="en">
          <body>{children}</body>
        </html>
      );
    }
  • Export metadata from a layout to share across child pages.
    export const metadata = {
      title: "My Blog",
      description: "Posts about web development"
    };

Special Files

  • Use error.tsx for error boundaries.
    // app/blog/error.tsx
    export default function Error({ error, reset }) {
      return (
        <div>
          <h2>Error loading blog</h2>
          <button onClick={() => reset()}>Try again</button>
        </div>
      );
    }
  • Use loading.tsx for Suspense fallbacks.
    // app/blog/loading.tsx
    export default function Loading() {
      return <p>Loading posts...</p>;
    }
  • Use not-found.tsx for 404 pages.
    // app/blog/[slug]/not-found.tsx
    export default function NotFound() {
      return <h1>Post not found</h1>;
    }
  • Use template.tsx for re-mounting a layout on navigation.
    // app/blog/template.tsx
    export default function Template({ children }) {
      return <div>{children}</div>; // Remounts on each navigation
    }
  • Use route.ts files to define API handlers inside the app router.
    // app/api/hello/route.ts
    export async function GET() {
      return Response.json({ message: "Hello" });
    }

Advanced Patterns

  • Group routes with parentheses (don't affect URL).
    app/
      (marketing)/
        page.tsx            # / (still at root)
        about/page.tsx      # /about
      (dashboard)/
        layout.tsx
        page.tsx            # /dashboard
  • Create catch-all routes with [...slug].
    app/
      docs/[...slug]/page.tsx    # /docs/a/b/c
  • Use optional catch-all [[...slug]].
    app/
      docs/[[...slug]]/page.tsx
      # Matches /docs, /docs/a, /docs/a/b/c
  • Use parallel routes with @ to render multiple pages simultaneously.
    app/
      @analytics/
        page.tsx
      @team/
        page.tsx
      layout.tsx            # Receives both slots as props
  • Use intercepting routes to show modals without full navigation.
    app/
      photos/
        [id]/
          page.tsx          # /photos/42 — full page
      (.)photos/
        [id]/
          page.tsx          # intercepted modal view

Tip: Use route groups (parentheses) to organize routes without affecting URLs — great for separating marketing and app sections.

Warning: Avoid deeply nested folder structures — keep routes 3–4 levels deep for clarity and maintainability.

Next.js API RoutesNext.js Caching and Revalidation