How File-System Based Routing Works in Next.js
Tags: beginners, react, javascript, codenewbie
Published: 2020-11-06 19:18:29

Next.js has file-system based routing built-in. You don't have to explicitly define the path in the router. It's as easy as adding a file inside the folder and you are done. There are multiple ways you can define a path using the file structure. Anything we add inside the `pages` directory is served as a path. Definitely there are exceptions like `_app.js` and `_document.js`.

There are two types of routes in Next.js
* API Routes: Any file you put inside `pages/api` is treated as an API endpoint and is served at `https://hostname/api/*`.
* Page Routes: Any file which is inside `pages` can be served as a web page to the user, it can be a Static Generation or Server-side Rendered. Any file which is inside `pages/api` is not treated as a web page.

We will go through all of these in detail in this blog post.

## Setup a Next.js Project

We will first create a Next.js project for this. We will name this `nextjs-routing`

```
npx create-next-app
# or
yarn create next-app
```

## Page Routing

* **Index Routing**

Once your project is ready it should look something like this. You can see that there is `index.js` inside the pages folder. So if you run your application and visit `http://localhost:3000` you will see the welcome next.js page, which is mapped to the `index.js`.

```
$ tree -I node_modules
.
├── README.md
├── package.json
├── pages
│   ├── _app.js
│   ├── api
│   │   └── hello.js
│   └── index.js
├── public
│   ├── favicon.ico
│   └── vercel.svg
├── styles
│   ├── Home.module.css
│   └── globals.css
└── yarn.lock
```

Here is how these pages are mapped to path by router.
`pages/index.js` -> `http://[hostname]/`
`pages/posts/index.js` -> `http://[hostname]/posts/`

Any `index.js` is mapped to the directory path it belongs to.

* **Nested Routing**

Now suppose you want to display deeply nested pages like dashboard settings etc.

`pages/about.js` -> `http://[hostname]/about/`
`pages/blog/hello.js` -> `http://[hostname]/blog/hello`
`pages/blog/series/hello.js` -> `http://[hostname]/blog/series/hello`

* **Dynamic Routing**

Suppose you don't have the exact route beforehand and it depends upon API data or some dynamic data. Here is how you can create these routes and map them.

`pages/blog/[slug].js` -> `http://[hostname]/blog/:slug` 

over here slug can be anything and you can use `getStaticPaths` to set the dynamic path.

`pages/blog/[...slug].js` -> `http://[hostname]/blog/hello` as well as `http://[hostname]/blog/series/hello` 

The above example is to catch all route. Basically, it can map a path to any level of nesting which happens after `blog/`. If you replace `[...slug].js` -> `[[...slug]].js`, it will match to `/blog` along with other routes like `blog/hello`, `blog/series/hello`.

> You can't use catch-all routes with the directory. Eg: `pages/blog/[[..slug]]/comments.js` will give you Error: Catch-all must be the last part of the URL.

`pages/[username]/dashboard` -> `http://[hostname]/:username/dashboard`

In the above example, a username can be a dynamic value.  It can be used to generate user-specific static pages.

## API Routing

`Next.js` provides a way to directly create API. You can consume these API from anywhere inside your project. Creating an API is pretty much straight forward, you just have to create a file inside `pages/api` and it gets mapped to `api/*`. It won't get exposed on the client-side and will only be used on the server-side. API routing is very much similar to page routing. Let's see how this works.

* **Index Routing**

The router will automatically route files named index to the root of the directory.

`pages/api/blog/index.js` -> `http://[hostname]/api/blog`

* **Nested Routing**

Now suppose you want to create a deeply nested API. You can create nested folder structure files and it will get mapped in the same way.

`pages/api/users/blog/create.js` -> `http://[hostname]/api/users/blog/create`

* **Dynamic Routing**

You can use brackets to define the dynamic routes for your API.

`pages/api/blog/[slug].js` -> `http://[hostname]/api/blog/hello`

In the above example, the slug can take any value. You can get this value inside your code.

`pages/api/blog/[...slug].js` -> `http://[hostname]/api/blog/hello` or `http://[hostname]/api/blog/hello/world`

The above example is to catch all routes. All the routes with `api/blog/*` get routed to this.

`pages/api/blog/[[...slug]].js` -> `http://[hostname]/api/blog` or `http://[hostname]/api/blog/hello` or `http://[hostname]/api/blog/hello/world`

> You can't use catch-all routes with the directory. Eg: `pages/api/blog/[[..slug]]/comments.js` will give you Error: Catch-all must be the last part of the URL.

The above example is for optional catch-all routes. Basically it makes the slug optional.

> 1. Predefined routes take precedence over dynamic routes. So if you have `pages/api/blog/create.js` and `pages/api/blog/[slug].js` then `pages/api/blog/create.js` gets mapped to `http://[hostname]/api/blog/create` and `pages/api/blog/[slug].js` gets mapped to `http://[hostname]/api/blog/abc`

> 2. There is no way to specify which REST calls are allowed on an API route, you have to handle them from your handler code.

Now suppose you want to create `api/blogs/:slug/comments/:commentId`. People you are familiar with the concept of resources in REST know there are use cases where we might need a nested resource.

`pages/api/blogs/[slug]/comments/[commentId].js` -> `http://[hostname]/api/blogs/:slug/comments/:commentId`


## Conclusion

Using Next.js routing is pretty much easy and straightforward and has very less overhead. It covers most of the use cases, I really couldn't think or find a use case which you won't be able to solve it.

> If you liked this post please share it with others so that it can help them as well. You can tag me on Twitter [@imumesh18](https://twitter.com/imuesh18). Also please follow me here and on Twitter for future blogs which I write over [here](https://blog.umesh.wtf)