Dynamic routes recipes from Next.js App Router
Tags: beginners, nextjs, react, codenewbie
Published: 2023-11-15 05:09:37

Next.js `App Router` has brought many improvements over its predecessor, `Page Router`. One of the significant improvements is the `routing` itself.

Next.js App Router uses the file-system-based router, where you create directories(aka folders) to define routes. You must create a special file called `page.js`(or .ts/.jsx/.tsx) under the directory to create a page for the route.

The top-level `app/` directory acts as the root route(`/`), and any directory you create under the app directory will create other route segments that map to a URL segment. You can also create the `nested route` by creating the subdirectories as shown in the image below.

![Next.js Routing](https://cdn.hashnode.com/res/hashnode/image/upload/v1699437649724/0a27401c-b823-41d0-ba50-9bfbdfa55243.png?border=1,CCCCCC&auto=compress align="center")

In Next.js App Router, a page is unique to a route. You can create one page per route by creating a `page.js` file under a directory that signifies a route segment.

```javascript
// /app/page.js
export default function Page() {
  return <h1>Home Page</h1>
}
```

If a directory doesn't have a corresponding `page.js` file, the respective route will be inaccessible and result in a 404, `page not found` error. The image below demonstrates that each route directory has a page file that creates the page for that route segment.

![Next.JS Page Routes](https://cdn.hashnode.com/res/hashnode/image/upload/v1699437815049/dc9efd80-052e-4310-ab4e-aaf8915cd74b.png?border=1,CCCCCC&auto=compress align="center")

So far, all the routes we have discussed are static and pre-defined, known beforehand to developers to construct the route segments. But what if we do not know the value to form a route segment? What if it is dynamic, like an id, name, or slug?

## Welcome Dynamic Routes

You create dynamic routes when you do not know the route segment name and want to create with dynamic data. For example, you may have a static route called `/blog`. Creating individual blog post routes under it will be too much overhead. You may want to create them using any dynamic data like id, name. or a slug.

> 💡 What is a slug?
> 
> Slug is an unique part of an URL that provides information about a web page. You should keep them simple, human-readable to help out with SEO. It appears at the end part of the URL after the backslash (“/”). For example, `how-to-learn` is the slug of the URL `https://tapascript.io/blog/how-to-learn`.

![dynamic routing](https://cdn.hashnode.com/res/hashnode/image/upload/v1699501930094/07a50b7c-97c2-415a-bd02-4dee368dd1e4.png?border=1,CCCCCC&auto=compress align="center")

## Let's Understand Things With Code

We understand things better with code. Let's do that. All the code used in this article is available on the [tapaScript GitHub repository](https://github.com/tapascript/teach-next-js).

First, we will create a project with the latest Next.js version. Open a terminal/command prompt and execute the following command. Make sure you have installed `Node.js 18` or above.

```bash
npx create-next-app@latest
```

Please provide the details asked. A few important things to note here.

* Opt for `App Router`
    
* The selection of TypeScript is your choice. If you are comfortable with it, you can select Yes. I'll use JavaScript code in this article as most developers will likely use it(however, I am a big TypeScript fan!).
    
* You may opt for the `src/` directory. I do that as I like to keep my project configuration files under the `src/` directory but outside of the `app/` directory. Here, we will assume to opt for it.
    

![steps](https://cdn.hashnode.com/res/hashnode/image/upload/v1699440868672/bfc613a0-71db-4f61-9d85-135edf31db4e.png?border=1,CCCCCC&auto=compress align="center")

Once done, change the directory to your project directory and install the dependencies using yarn/npm/pnpm/bun, whatever you want. Then, start the server locally using the `yarn dev` or its npm/pnpm/bun equivalent commands.

```bash
> cd teach-next-js
> yarn
> yarn dev # or npm run dev or pnpm dev or bun dev
```

The app will be available on the `localhost:3000` by default. As you see in the image below, the `app/` directory under the `src/` directory signifies the top-level route `/`. The `page.js` file under the `app/` directory provides us with the page for that route.

![folder to route](https://cdn.hashnode.com/res/hashnode/image/upload/v1699441316324/f209ea19-7490-4b60-95c8-477902eb8711.png?border=1,CCCCCC&auto=compress align="center")

Let's clear the existing code in the `page.js` file and put a simple ReactJS component like this:

```javascript
export default function Home() {
  return (
    <div className="flex justify-center p-2">
      <p className="text-3xl">
        Home Page
      </p>
    </div>
  )
}
```

Now, our home page(on the route segment `/`) will look like this:

![Home Page](https://cdn.hashnode.com/res/hashnode/image/upload/v1699441715002/7233c88b-63b4-4193-b40b-82e4122cdfee.png?border=1,CCCCCC&auto=compress align="center")

### Create More Routes

Let's create a `/blog` route segment. To do that, we will create a `blog/` directory under the `app/` directory.

![Added Blog](https://cdn.hashnode.com/res/hashnode/image/upload/v1699441787679/15a1d965-752f-4975-b734-0f2e6180b416.png?border=1,CCCCCC&auto=compress align="center")

Now you will have a `/blog` route segment. However, it will not be accessible publicly because we have not defined a page for it yet.

![404 page](https://cdn.hashnode.com/res/hashnode/image/upload/v1699441815478/495f151e-00bc-48e9-a3f1-737579ac723f.png?border=1,CCCCCC&auto=compress align="center")

Let's create a `page.js` file under the `blog/` directory with the following content.

```javascript
const BlogPage = () => {
  return (
    <>
      <p className="text-3xl">Blog Page</p>
    </>
  )
}

export default BlogPage;
```

We will see the blog page rendered successfully. It is a simple page with a paragraph of text.

![blog page](https://cdn.hashnode.com/res/hashnode/image/upload/v1699441969781/a9578e95-41b4-4ee6-a45a-3878ffe9e5e0.png?border=1,CCCCCC&auto=compress align="center")

### Create Nested Routes

Let us now create a couple of nested routes like `/about/form` and `/about/tax`. You guessed it right! We will have to create an `about/` directory and then two sub-directories under it. Those are `form/` and `tax/`.

Now, to make all three routes accessible, we need to create a `page.js` file under each of the directories.

![About Page](https://cdn.hashnode.com/res/hashnode/image/upload/v1699442187430/fb72b93f-0f0f-46e9-bae8-b50e767d84c0.png?border=1,CCCCCC&auto=compress align="center")

Here is an example page for the `/about` route segment. You can create something similar for the pages of `/about/form` and `/about/tax`.

```javascript
const AboutPage = () => {
  return (
    <>
      <p className="text-3xl">About Page</p>
    </>
  )
}

export default AboutPage;
```

Here is how each of the pages may appear for each of the routes.

![All Pages](https://cdn.hashnode.com/res/hashnode/image/upload/v1699442384151/e7637ba2-fb2d-4b50-9add-c2ff88ac3127.png?border=1,CCCCCC&auto=compress align="center")

### Create Dynamic Routes

Now it's time we start understanding dynamic route segments with code. You can create a dynamic route segment by wrapping the directory name in square brackets(`[]`). For example, `[name]`, `[slug]`, `[id]`, etc.

Taking forward the example of a blog and its posts, the individual posts can include a route like this, `/blog/[slug]/page.js`. Here `[slug]` is the dynamic route segment.

Create a directory named `[slug]` under the `blog/` directory and a `page.js` file under the `blog/[slug]/`.

![blog with slug](https://cdn.hashnode.com/res/hashnode/image/upload/v1699442782666/9afb0cc7-3c7d-4c66-9b5c-b9c80b34c2c1.png?border=1,CCCCCC&auto=compress align="center")

All dynamic segments are passed as the `params` prop to the `page`. We can destructure the dynamic route segment value from the `params` prop. Let's create the content for the dynamic route page with the following code.

```javascript
const BlogPost = ({params: {slug}}) => {
  return(
    <p className="text-2xl">
      Showing the blog post for the 
      slug <strong>{slug}</strong>
    </p>
  )
}

export default BlogPost;
```

The page has received a `params` prop, and we can extract the `slug` value from it. Now, you can do whatever logic you need using the `slug` value. You can use it to make a network call and get details to render on the page, or you can just render it on the page, as shown below.

![blog slugs](https://cdn.hashnode.com/res/hashnode/image/upload/v1699443081016/6eb89c51-dcf1-47c4-9870-3e60d08ba73d.png?border=1,CCCCCC&auto=compress align="center")

### Create Dynamic **Catch-all Segments**

You can broaden the use of the dynamic route segment(`[slug]`) to a `catch-all` route segment by adding an ellipsis inside the brackets`[...slug]`.

For example `/app/store/[...slug]/page.js` will match `/store/book`, `/store/design`, and also `/store/book/novels`, `/store/design/shoes`, `/store/design/shoes/boot`, and so on.

Create a `store/` directory under the `app/` directory. Now, create a directory with the name `[...name]` under the `app/store/`.

![ctach-all](https://cdn.hashnode.com/res/hashnode/image/upload/v1699443465222/7691173f-f24f-4fc5-811f-8a8cc246ea6e.png?border=1,CCCCCC&auto=compress align="center")

The `page.js` file under the `app/store/[...name]` will define a page for the catch-all route segment. This page component is quite similar to the page component we have seen above for the dynamic routes. However, notice that we are extracting `name` instead of `slug` here because we have used `[...name]` as the directory name.

```javascript
const StorePage = ({params: {name}}) => {
  console.log(name);
  return(
    <p className="text-2xl">
      Showing the store page for the 
      name <strong>{name}</strong>
    </p>
  )
}

export default StorePage;
```

Now, when you try the route `localhost:3000/store/a`, the `params` returns `{name: ['a']}`. We are printing that on the console and browser.

![catch all example 1](https://cdn.hashnode.com/res/hashnode/image/upload/v1699515301200/c044b053-3a27-4c6d-86b4-1e54937e88d1.png?border=1,CCCCCC&auto=compress align="center")

You can also catch the route `localhost:3000/store/a/b` with the same, and the `params` prop value will be `{name: ['a', 'b']}`.

![catch all example 2](https://cdn.hashnode.com/res/hashnode/image/upload/v1699515341728/4fd73b59-7192-483a-8578-c5a25015dfeb.png?border=1,CCCCCC&auto=compress align="center")

### Create Optional Dynamic **Catch-all Segments**

But hang on! How about the route `/store`? It gives us 404, page not found.

![store route](https://cdn.hashnode.com/res/hashnode/image/upload/v1699444221329/7f93764b-e147-4ba7-8b6c-f813940d68f5.png?border=1,CCCCCC&auto=compress align="center")

Yes! One way to fix that is by creating a `page.js` file inside the `app/store/` directory. If you don't want that, you can make the catch-all segment as an `optional catch-all` segment by wrapping the parameter(or directory name) in double square brackets, `[[...name]].`

![optional catch all](https://cdn.hashnode.com/res/hashnode/image/upload/v1699444308982/c90e2199-9a5c-418a-ab73-86e9e22736a9.png?border=1,CCCCCC&auto=compress align="center")

Now even the `/store` route page will be served from the `app/store/[[...name]]/page.js`. However, in this case, the value of `name` will be `undefined` and the `params` prop value will be `{}`.

![optional catch all 2](https://cdn.hashnode.com/res/hashnode/image/upload/v1699515258928/a25874ff-2f59-462a-8a42-5d1d1e0d41ed.png?border=1,CCCCCC&auto=compress align="center")

That's all. Thanks for reading it. I hope it was insightful. If you liked the tutorial, please post likes and share it in your circles.

## One Last Thing...

I am a self-declared `Next.js` evangelist who loved this framework from its very beginning days. With the inclusion of the App Router, the affection has gone higher 😊.

I have a [full-fledged playlist](https://www.youtube.com/watch?v=eX9KA48IZes&list=PLIJrr73KDmRwz_7QUvQ9Az82aDM9I8L_8&index=6) on my YouTube channel([tapaScript](https://www.youtube.com/tapasadhikary?sub_confirmation=1)) that will teach you to build projects with Next.js, from clarifying fundamental concepts to coding and tasks.

You may want to check it out.

> {% youtube eX9KA48IZes %} 

---

Let's connect. I share knowledge on web development, content creation, Open Source, and careers on these platforms.

* [**tapaScript on YouTube**](https://www.youtube.com/tapasadhikary?sub_confirmation=1)
    
* [**X(eka Twitter)**](https://twitter.com/tapasadhikary)
    
* [**LinkedIn**](https://www.linkedin.com/in/tapasadhikary/)
    
* [**GitHub**](https://github.com/atapas)