Skip to main content

Overview

Next.js App Router uses a file-based routing system where the file structure in the app directory directly maps to URL routes. This approach simplifies routing configuration and provides better performance through automatic code splitting.

Route Segments

Each folder in the app directory represents a route segment:
app/
├── page.tsx          # / (root route)
├── about/
│   └── page.tsx      # /about
├── blog/
│   ├── page.tsx      # /blog
│   └── [slug]/
│       └── page.tsx  # /blog/[slug] (dynamic route)
└── dashboard/
    ├── page.tsx      # /dashboard
    └── settings/
        └── page.tsx  # /dashboard/settings

Special Files

page.tsx

  • Makes a route publicly accessible
  • Required for a route to be accessible
  • Defines the UI for that route

layout.tsx

  • Shared UI for multiple pages
  • Wraps child layouts and pages
  • Maintains state during navigation

loading.tsx

  • Loading UI for a route segment
  • Shows while page is loading
  • Automatically wraps page and children

error.tsx

  • Error UI for a route segment
  • Catches errors in child segments
  • Provides error boundaries

not-found.tsx

  • 404 page for a route segment
  • Shows when route is not found
  • Can be nested at different levels

template.tsx

  • Re-renders on every navigation
  • Useful for animations and transitions
  • Creates new instance for each route
Use parentheses to group routes without affecting the URL structure:
app/
├── (auth)/
│   ├── login/
│   │   └── page.tsx    # /login
│   └── register/
│       └── page.tsx    # /register
├── (dashboard)/
│   ├── profile/
│   │   └── page.tsx    # /profile
│   └── settings/
│       └── page.tsx    # /settings
└── page.tsx            # / (root)

Single Dynamic Segment

app/
└── blog/
    └── [slug]/
        └── page.tsx    # /blog/[slug]
// app/blog/[slug]/page.tsx
interface PageProps {
  params: { slug: string };
}

export default function BlogPost({ params }: PageProps) {
  return <h1>Blog Post: {params.slug}</h1>;
}

Multiple Dynamic Segments

app/
└── shop/
    └── [category]/
        └── [product]/
            └── page.tsx    # /shop/[category]/[product]
// app/shop/[category]/[product]/page.tsx
interface PageProps {
  params: {
    category: string;
    product: string;
  };
}

export default function ProductPage({ params }: PageProps) {
  return (
    <div>
      <h1>Category: {params.category}</h1>
      <h2>Product: {params.product}</h2>
    </div>
  );
}

Catch-All Routes

app/
└── docs/
    └── [...slug]/
        └── page.tsx    # /docs/[...slug]
// app/docs/[...slug]/page.tsx
interface PageProps {
  params: { slug: string[] };
}

export default function DocsPage({ params }: PageProps) {
  return <h1>Docs: {params.slug.join("/")}</h1>;
}

Route Organization

1

Group Related Routes

Use route groups to organize related pages without affecting URLs
2

Use Descriptive Names

Choose clear, descriptive folder and file names
3

Keep Routes Flat

Avoid deeply nested routes when possible
4

Use Dynamic Routes Wisely

Use dynamic routes for content that changes frequently

Performance Considerations

Automatic Code Splitting

  • Each route is automatically code-split
  • Only loads code needed for current route
  • Improves initial page load performance

Prefetching

  • Links are automatically prefetched
  • Improves navigation performance
  • Can be disabled with prefetch=

Before (React Router)

// App.js
import { BrowserRouter, Routes, Route } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/blog/:slug" element={<BlogPost />} />
      </Routes>
    </BrowserRouter>
  );
}

After (Next.js App Router)

app/
├── page.tsx              # /
├── about/
│   └── page.tsx          # /about
└── blog/
    └── [slug]/
        └── page.tsx      # /blog/[slug]

Nested Layouts

app/
├── layout.tsx            # Root layout
├── dashboard/
│   ├── layout.tsx        # Dashboard layout
│   ├── page.tsx          # /dashboard
│   └── settings/
│       └── page.tsx      # /dashboard/settings

Route Protection

// app/dashboard/layout.tsx
import { redirect } from "next/navigation";

export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  // Check authentication
  const isAuthenticated = checkAuth();

  if (!isAuthenticated) {
    redirect("/login");
  }

  return (
    <div>
      <h1>Dashboard</h1>
      {children}
    </div>
  );
}
Problem: Route returns 404 even though file exists Solution: Ensure the file is named page.tsx and is in the correct directory
Problem: Layout styles not showing on child routes Solution: Check that layout.tsx is in the correct directory and wraps children
Problem: Dynamic route parameters not accessible Solution: Ensure the page component receives params as props and handles the correct parameter names
Key Takeaway: Next.js file-based routing simplifies route management by using the file system structure to define routes. This approach provides better performance through automatic code splitting and makes routing more intuitive for developers.