Skip to main content

Next.js Nested Routes

In modern web applications, organizing your pages in a logical hierarchy is essential for maintaining a clear structure as your project grows. Next.js provides an elegant solution for this through its file-system based routing with support for nested routes. This feature allows you to create intuitive URL hierarchies that match your application's information architecture.

Introduction to Nested Routes

Nested routes in Next.js allow you to create URLs with multiple segments that represent different levels of your application's structure. For example, you might want URLs like:

  • /blog for your blog homepage
  • /blog/posts for a list of all posts
  • /blog/posts/my-first-post for a specific post

This hierarchical organization helps users understand where they are in your application and makes your codebase more maintainable.

How Next.js Implements Nested Routes

Next.js uses a file-system based approach to routing. The directory structure in your pages folder (in Next.js 12 and earlier) or app folder (in Next.js 13+ with the App Router) directly maps to URL paths in your application.

Pages Router (Next.js 12 and earlier)

Let's see how nested routes work in the traditional Pages Router:

pages/
index.js # Route: /
about.js # Route: /about
blog/
index.js # Route: /blog
posts/
index.js # Route: /blog/posts
[slug].js # Route: /blog/posts/any-post-slug

Each directory creates a new segment in the URL path, and each index.js file represents the default page for that route.

App Router (Next.js 13+)

In the newer App Router, the concept remains similar but with some structural differences:

app/
page.tsx # Route: /
about/
page.tsx # Route: /about
blog/
page.tsx # Route: /blog
posts/
page.tsx # Route: /blog/posts
[slug]/
page.tsx # Route: /blog/posts/any-post-slug

In the App Router, each route segment is represented by a folder, and the page.tsx (or page.js) file defines the UI for that route.

Creating Your First Nested Routes

Let's walk through creating a simple blog structure with nested routes:

Example 1: Basic Blog Structure (Pages Router)

First, let's create the necessary files:

jsx
// pages/blog/index.js
export default function BlogHome() {
return (
<div>
<h1>Welcome to My Blog</h1>
<p>This is the blog homepage. Check out my latest posts below!</p>
{/* Post list would go here */}
</div>
);
}
jsx
// pages/blog/posts/index.js
export default function AllPosts() {
return (
<div>
<h1>All Blog Posts</h1>
<ul>
<li><a href="/blog/posts/getting-started-with-nextjs">Getting Started with Next.js</a></li>
<li><a href="/blog/posts/mastering-nested-routes">Mastering Nested Routes</a></li>
<li><a href="/blog/posts/advanced-next-features">Advanced Next.js Features</a></li>
</ul>
</div>
);
}
jsx
// pages/blog/posts/[slug].js
import { useRouter } from 'next/router';

export default function BlogPost() {
const router = useRouter();
const { slug } = router.query;

return (
<div>
<h1>Blog Post: {slug}</h1>
<p>This is the content of the blog post about {slug}.</p>
<a href="/blog/posts">Back to all posts</a>
</div>
);
}

Example 2: Blog Structure with App Router

Let's implement the same structure using the App Router:

jsx
// app/blog/page.tsx
export default function BlogHome() {
return (
<div>
<h1>Welcome to My Blog</h1>
<p>This is the blog homepage. Check out my latest posts below!</p>
{/* Post list would go here */}
</div>
);
}
jsx
// app/blog/posts/page.tsx
import Link from 'next/link';

export default function AllPosts() {
return (
<div>
<h1>All Blog Posts</h1>
<ul>
<li><Link href="/blog/posts/getting-started-with-nextjs">Getting Started with Next.js</Link></li>
<li><Link href="/blog/posts/mastering-nested-routes">Mastering Nested Routes</Link></li>
<li><Link href="/blog/posts/advanced-next-features">Advanced Next.js Features</Link></li>
</ul>
</div>
);
}
jsx
// app/blog/posts/[slug]/page.tsx
export default function BlogPost({ params }: { params: { slug: string } }) {
const { slug } = params;

return (
<div>
<h1>Blog Post: {slug}</h1>
<p>This is the content of the blog post about {slug}.</p>
<a href="/blog/posts">Back to all posts</a>
</div>
);
}

Shared Layouts for Nested Routes

One of the powerful features of nested routes is the ability to create shared layouts for related pages.

With Pages Router

In the Pages Router, you'd typically use a custom _app.js or component composition:

jsx
// components/BlogLayout.js
export default function BlogLayout({ children }) {
return (
<div className="blog-container">
<header>
<h1>My Amazing Blog</h1>
<nav>
<a href="/blog">Home</a>
<a href="/blog/posts">All Posts</a>
<a href="/blog/about">About</a>
</nav>
</header>
<main>{children}</main>
<footer>© {new Date().getFullYear()} My Blog</footer>
</div>
);
}

Then use it in your pages:

jsx
// pages/blog/posts/index.js
import BlogLayout from '../../../components/BlogLayout';

export default function AllPosts() {
return (
<BlogLayout>
<h1>All Blog Posts</h1>
{/* Post list */}
</BlogLayout>
);
}

With App Router

The App Router introduces a more elegant solution with layout files:

jsx
// app/blog/layout.tsx
export default function BlogLayout({ children }: { children: React.ReactNode }) {
return (
<div className="blog-container">
<header>
<h1>My Amazing Blog</h1>
<nav>
<a href="/blog">Home</a>
<a href="/blog/posts">All Posts</a>
<a href="/blog/about">About</a>
</nav>
</header>
<main>{children}</main>
<footer>© {new Date().getFullYear()} My Blog</footer>
</div>
);
}

This layout will automatically apply to all routes under /blog.

Real-World Examples

E-commerce Category Structure

A common use case for nested routes is an e-commerce site with categories and products:

app/
shop/
page.tsx # /shop (all products)
categories/
page.tsx # /shop/categories (all categories)
[category]/
page.tsx # /shop/categories/electronics
products/
page.tsx # /shop/categories/electronics/products
[productId]/
page.tsx # /shop/categories/electronics/products/12345

Example implementation for a product page:

jsx
// app/shop/categories/[category]/products/[productId]/page.tsx
async function getProductData(category, productId) {
// In a real app, you would fetch this from an API or database
return {
id: productId,
name: `Product ${productId}`,
category,
price: 99.99,
description: 'This is a great product!'
};
}

export default async function ProductPage({ params }) {
const { category, productId } = params;
const product = await getProductData(category, productId);

return (
<div className="product-page">
<nav className="breadcrumbs">
<a href="/shop">Shop</a> &gt;
<a href={`/shop/categories/${category}`}>{category}</a> &gt;
<span>{product.name}</span>
</nav>

<div className="product-details">
<h1>{product.name}</h1>
<p className="category">Category: {product.category}</p>
<p className="price">${product.price}</p>
<div className="description">
<h2>Description</h2>
<p>{product.description}</p>
</div>
<button className="add-to-cart">Add to Cart</button>
</div>
</div>
);
}

Documentation Site Structure

Another common use case is a documentation site:

app/
docs/
page.tsx # /docs (documentation home)
getting-started/
page.tsx # /docs/getting-started
guides/
page.tsx # /docs/guides (list of guides)
[guideId]/
page.tsx # /docs/guides/installation
api-reference/
page.tsx # /docs/api-reference
[apiSection]/
page.tsx # /docs/api-reference/auth
[methodName]/
page.tsx # /docs/api-reference/auth/login

Best Practices for Nested Routes

  1. Keep URL Structure Intuitive: Design URLs that make sense to users and reflect the hierarchy of your content.

  2. Use Dynamic Routes Sensibly: While you can create deeply nested dynamic routes ([...slug] or [[...slug]]), keep them manageable.

  3. Leverage Shared Layouts: Create layout components for sections that share common UI elements.

  4. Consider SEO: Ensure your URL structure is SEO-friendly. Search engines prefer logical hierarchies.

  5. Handle Loading and Error States: Especially in the App Router, create loading.tsx and error.tsx files for each route segment that needs them.

  6. Use Link Component: Always use Next.js's Link component rather than standard <a> tags for client-side navigation between routes.

Common Pitfalls and Solutions

Pitfall 1: Excessive Nesting

Problem: Creating too many levels of nesting can make URLs unwieldy and code hard to maintain.

Solution: Aim for a maximum of 3-4 levels of nesting. Consider a flatter structure with more descriptive segment names if necessary.

Pitfall 2: Duplicate Content

Problem: Creating multiple routes that serve the same content.

Solution: Use redirects or canonical URLs to indicate the preferred version of duplicate content.

jsx
// app/old-page/page.tsx
import { redirect } from 'next/navigation';

export default function OldPage() {
redirect('/new-page');
}

Pitfall 3: Inconsistent Navigation

Problem: Users get confused when navigation options change between nested pages.

Solution: Use consistent layouts and breadcrumbs to help users understand their location in the site hierarchy.

Summary

Nested routes in Next.js provide a powerful way to organize your application's content in a logical hierarchy. By leveraging the file-system based routing system, you can:

  • Create intuitive URL structures that match your information architecture
  • Share layouts and components across related pages
  • Build complex multi-level navigation systems
  • Maintain clean code organization as your project grows

Whether you're using the Pages Router in older Next.js versions or the new App Router in Next.js 13+, nested routes follow the same core principle: the directory structure of your project determines the URL paths of your application.

Additional Resources

  1. Next.js Documentation on Routing
  2. Next.js App Router Documentation
  3. Learn Next.js - Official Tutorial

Exercises

  1. Basic Blog: Create a simple blog with nested routes for categories and posts.

  2. Navigation Challenge: Implement breadcrumb navigation that dynamically shows the current location in your nested route structure.

  3. Admin Dashboard: Design a more complex nested route structure for an admin dashboard with sections for users, products, and analytics.

  4. Route Groups: Experiment with route groups (folders with parentheses like (marketing)) in the App Router to organize routes without affecting the URL structure.

  5. Dynamic Routes: Create a wiki-style application that uses catch-all routes ([...slug]) to handle arbitrary levels of nesting.

By mastering nested routes in Next.js, you'll be able to build applications with clear, organized structures that scale well as your project grows.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)