Next Js: The app router in practice
When the new app router came out in Next JS, I updated my website to use it. I wanted to understand first-hand how it works. I wanted to understand the changes and whether they are worth the effort.
I’ve already talked about React Server Components in theory. Here I’d like to go through some practical lessons I learnt while coding.
I will focus on the basics: how the app router works. There is much more to cover, such as SEO features, translation, and managing content. I’m splitting that up because I’d like to keep this short, but I will be covering that later.
So here is how the app router differs from the page directory router. Let’s dive in.
The basics of the app directory router
First, as you might know, the app router uses the filesystem in the app directory to link a URL to specific files in the filesystem. That much was also true of the pages
folder router.
Let’s start with the basics: Let’s say I have a blog/
directory that contains a page.tsx
The first thing to note here is that the file is called “page”, and not “index”.
Now, when I navigate to the blog/
path of my website, the component inside the page.tsx
file will be rendered. That much is the same as the pages
router.
However, in the pages
router, you could also route using filenames. For example, you could have an about.tsx
that would map to the /about
URI. That no longer works in the app
router.
Instead of thinking in files and folders, you need to think only in folders.
The app
router allows you to have additional specialised files in each directory. These add functionality. For example, I can have a file to manage errors, one for the layout or the loading interface.
Now, what else can the app
router do?
Dynamic routes
In my example, the blog
folder has a fixed name. However, Next also supports folders and subfolders with dynamic names, which map to dynamic routes. These use the square brackets notation. Allow me to explain with an example.
In my case, the blog/
directory has a folder called tag
, another called category
, and a third one called [slug]
, between square brackets. This means that blog/tag/
will map to the tag
subfolder, and blog/category/
will map to the category
subfolder. But any other path that starts with blog/
will map to the [slug]
folder.
When there is a dynamic path, the router passes the values of the parameter to the component in the page.tsx
file, using a paras
prop.
For example, if we take a look at the page.tsx
file in the [slug]
folder of my blog folder. Here, the params
object contains a slug
member (and also a lang
member because my website is multilingual).
export default async function BlogPostPage({ params: {lang, slug } }: Params) {
Using the value of the slug
and the lang
parameters, I can then determine which article has been requested and fetch it:
const post = await findPostBySlug(lang, slug);
(I won’t go into the details of the findPostBySlug
because it isn’t specific to the app/
router and depends on how you fetch your content)
Managing errors and redirects
404 error management
Of course, if there isn’t any content that matches, I can simply return an error. Since my page is a React Server Component, this is relatively simple: I start by importing the notFound
function from next/navigation
. Then if I haven’t found the content, I return a call to the function.
import { notFound } from 'next/navigation';
/* ... */
export default async function BlogPostPage({ params: {lang, slug } }: Params) {
const post = await findPostBySlug(lang, slug);
if (!post) {
return notFound();
}
// here continue as normal
}
Managing redirects
In my case, I also want to be able to deprecate content and redirect to new pages. How do I go about that?
First, I import the redirect
function from next/navigation
. Then, if my content has a redirect URL, I redirect to it.
if (post.redirectUrl) {
redirect(post.redirectUrl);
}
We help you better understand software development. Receive the latest blog posts, videos, insights and news from the frontlines of web development
Parenthesis directories
Another point worth mentioning, which caused a bit of confusion for me when I was starting, is that you can also define a directory with a name inside parenthesis.
This helps organise your code but doesn’t impact the routing. So, for instance, if you wanted to group all your e-commerce stuff, you could create a (e-commerce)
folder. Then (for example) the (e-commerce)/courses
folder would map to the courses/
URL (and not to e-commerce/courses
).
The router file
There is much more to discover. The documentation is still being written in some cases! One thing I did want to point out, though, was that instead of the page.tsx
file, you could instead have a route.ts
. This allows you to code lower-level behaviour where you specify exactly what happens when a request hit the route with a specific HTTP verb.
This allows you to write APIs but also non-page content, like an RSS feed.
Now, there is more to cover concerning the app
router.
First, its SEO features, how to manage metadata, create sitemaps, and the robots file.
And second, how to translate Next JS websites. Because all my favourite existing libraries use client-side hooks that don’t work in the app
directory, so I had to add my own.