Skip to content

App Router Navigation

App Router Structure and Navigation

The App Router in Next.js 13+ introduces a file-based routing system that organizes routes using a directory structure. This approach enables nested routing, dynamic segments, and seamless integration with API routes, forming the foundation for scalable, maintainable applications. This section explores how to implement these patterns effectively.


Nested Routing with Layouts

Nested routing in the App Router is achieved by organizing routes into a hierarchical directory structure. Each route can define a layout.js file to wrap child routes, creating a shared UI context.

Example: Nested Layout Structure

app/
  dashboard/
    layout.js
    index.js
    users/
      layout.js
      index.js
  • app/dashboard/layout.js wraps dashboard/index.js and dashboard/users/....
  • app/dashboard/users/layout.js wraps user-specific pages.

Use the useRouter hook to navigate programmatically:

import { useRouter } from 'next/navigation';

function Dashboard() {
  const router = useRouter();
  return (
    <button onClick={() => router.push('/dashboard/users')}>
      View Users
    </button>
  );
}

Diagram: Nested Route Hierarchy

app/
├── dashboard/
│   ├── layout.js
│   ├── index.js
│   └── users/
│       ├── layout.js
│       └── index.js
└── ...

Dynamic Segments

Dynamic segments allow routes to handle variable parameters, such as /posts/[id]. These segments are defined using square brackets in the route file name.

Example: Dynamic Post Route

app/
  posts/
    [id].js
  • The [id] segment captures the ID from the URL.
  • Access parameters via the params object:
    export async function loader({ params }) {
      const postId = params.id;
      // Fetch post data based on `postId`
    }
    

Static Generation with generateStaticParams

For static routes, use generateStaticParams to pre-render dynamic segments:

export async function generateStaticParams() {
  const posts = await fetchPosts(); // Fetch all post IDs
  return posts.map(post => ({ id: post.id }));
}


API Route Integration

API routes in the App Router are defined in the app/api directory. These routes handle HTTP requests and can be used for server-side logic, data fetching, or authentication.

Example: Simple API Route

app/
  api/
    posts/
      route.js
  • app/api/posts/route.js handles requests to /api/posts.
  • Use the Request object to parse incoming data:
    export async function GET(request) {
      const searchParams = request.nextUrl.searchParams;
      const postId = searchParams.get('id');
      // Return JSON response
      return new Response(JSON.stringify({ id: postId }), { status: 200 });
    }
    

Diagram: API Route Structure

app/
└── api/
    └── posts/
        └── route.js

Key takeaways

  • Nested routing is achieved via directory hierarchies and layout.js files, enabling shared UI contexts.
  • Dynamic segments use [id] notation to capture variable parameters, with params for access.
  • API routes are defined in app/api/, handling HTTP requests with server-side logic.