image of blog

Next.js 15 routing – A Complete Guide (Nested & Dynamic Routes)

Routing in Next.js

Next.js has a file-system-based routing system. The URLs you can access in your browser are determined by how you organize your files and folders within your project.

Understanding the src/app Directory

In Next.js (when using the App Router), the src/app directory serves as the foundation for your application's structure. Key files inside this directory include:

  • layout.tsx – Defines the layout for your application, allowing you to persist UI elements across different pages.
  • page.tsx – Represents the content of a particular route.

Scenario 1: Creating a Homepage

Suppose you want to have a homepage accessible at:

http://localhost:3000/

To achieve this, ensure that a page.tsx file exists inside the src/app directory. By default, this file is created when you initialize a Next.js project.

Scenario 2: Creating Additional Pages

Now, let's say you want to create additional pages with different URLs.

Creating an About Page

To create a page accessible at:

http://localhost:3000/about

Follow these steps:

  1. Inside the src/app directory, create a new folder named about.
  2. Inside about, create a page.tsx file.
  3. Add the following code:
export default function About() {
   return <h1>Hello from About</h1>
}

Creating a Custom Page (e.g., Ramx Page)

If you want a page accessible at:

http://localhost:3000/ramx

Follow the same steps as above:

  1. Inside src/app, create a folder named ramx.
  2. Inside ramx, create a page.tsx file.
  3. Add the following code:
export default function Ramx() {
   return <h1>Hello from Ramx</h1>
}

Folder Structure for the Pages

After adding these pages, your src/app directory will look like this:

src/app/
   layout.tsx  - Defines layout structure
   page.tsx  - Homepage
   about/
      page.tsx  - About Page
   ramx/
      page.tsx  - Ramx Page

Nested Routes

Scenario 3: Creating Blog Pages

Suppose you want to handle the following routes:

Steps:

  1. First, create a blog folder inside src/app.
  2. Inside blog, create a page.tsx file.

This will create the route:

http://localhost:3000/blog

Handling /blog/first and /blog/second

Brute force method (Good for small projects, but not recommended for scalability):

Manually create separate folders:

src/app/blog/first/page.tsx
src/app/blog/second/page.tsx

Each file should contain:

export default function FirstBlog() {
   return <h1>First Blog Post</h1>
}
export default function SecondBlog() {
   return <h1>Second Blog Post</h1>
}

routes


Dynamic Routing

Scenario 4: Creating a Product Listing Page

Suppose you want to create a product listing page where:

  • /products lists all products.
  • Individual product pages exist at /products/product-1, /products/product-2, etc.

Each product also has a details page, such as /products/1.

Brute Force Method (Not Scalable)

Manually create:

src/app/products/product-1/page.tsx
src/app/products/product-2/page.tsx
src/app/products/product-3/page.tsx

Instead of manually creating pages for each product, use dynamic routing.

Steps:

  1. Create a folder named [productId] inside src/app/products/.
  2. Inside [productId], create a page.tsx file.

Your folder structure should look like:

src/app/products/
   page.tsx   # Product listing page
   [productId]/
      page.tsx  # Dynamic product page

Code for Dynamic Product Page

export default function ProductPage({ params }: { params: { productId: string } }) {
   return <h1>Product ID: {params.productId}</h1>;
}

Now, if you visit http://localhost:3000/products/100, the params.productId will be 100, and it will render dynamically.


Nested Dynamic Routes

Scenario 5: Category & Product Pages

Let's say you need URLs like:

Steps to Implement:

  1. Create a categories folder inside src/app.
  2. Inside categories, create a dynamic [categoryId] folder.
  3. Inside [categoryId], create a dynamic [subCategoryId] folder.
  4. Add page.tsx inside both folders.

Folder Structure:

src/app/categories/
   [categoryId]/
      page.tsx  # Category page
      [subCategoryId]/
         page.tsx  # Sub-category page

Code for Category Page:

export default function CategoryPage({ params }: { params: { categoryId: string } }) {
   return <h1>Category: {params.categoryId}</h1>;
}

Code for Sub-Category Page:

export default function SubCategoryPage({ params }: { params: { categoryId: string, subCategoryId: string } }) {
   return <h1>{params.subCategoryId} in {params.categoryId}</h1>;
}

Catch-All Segments

Scenario 6: Handling Unknown Nested Routes

If you need to handle any level of nested paths, use a catch-all segment.

Example URLs:

How to Implement:

  1. Inside src/app, create a docs folder.
  2. Inside docs, create a [...slug] folder (the three dots indicate "catch-all").
  3. Inside [...slug], create page.tsx.

Folder Structure:

src/app/docs/
   [...slug]/
      page.tsx

Code for Catch-All Route:

export default function DocsPage({ params }: { params: { slug?: string[] } }) {
   return (
      <div>
         <h1>Docs Page</h1>
         <p>Path: {params.slug ? params.slug.join(" / ") : "Home"}</p>
      </div>
   );
}

Do check out the previous blog