Mastering NextJS Parallel Routes
Recently I came across a powerful routing feature in Next.js that completely changed how I thought about structured complex web applications.
I had an application where there were multiple components which needed to load and change independently. My use case was more than just needing different props - I essentially needed to have multiple children that sat in different parts of my layout.
And that's when I discovered NextJS Parallel Routes, which were introduced in NextJS 14.
What Are Parallel Routes?
Parallel Routes are an advanced routing mechanism that lets you show multiple pages at once within the same layout.
In regular websites, when you click a link, the whole page changes. But with Parallel Routes, only certain parts change while others stay the same. This is perfect for:
- Data-heavy dashboards where you need to see multiple sections
- An e-commerce site where you want to show products and a trolley independently
- Social media feeds with different content types
- Authentication flows where only part of the page changes when the user is logged in
How Do Parallel Routes Work?
The magic of Parallel Routes happens with special folders known as 'slots' which are prefixed with an @
symbol. For example @analytics
.
Let's say you're building a dashboard with three sections:
- Main dashboard
- Analytics section
- Revenue section
Here's how you'd set up your folder structure:
app/
└── dashboard/
├── layout.tsx
├── page.tsx (Main dashboard page)
├── @analytics/
│ └── page.tsx (Analytics section)
└── @revenue/
└── page.tsx (Revenue section)
These slots automatically become props that are passed to the layout - you don't need to import them. So you can use them like so:
export default function DashboardLayout({
children,
analytics,
revenue,
}) {
return (
<div>
<nav>Dashboard Links</nav>
<div>{children}</div>
<div>{analytics}</div>
<div>{revenue}</div>
</div>
);
}
Now you understand how they work, let's take a look at some of the cool things you can do with them:
1. Independent Loading and Error States
NextJS's App Router already has great handling for loading states, and this is extended with parallel routes which are able to have their own loading states!
This enables you to partially load your page and allow your users to interact even while other sections are still loading. Like you would for any NextJS loading state you can add loading to parallel route by simply adding a loading.tsx
file inside each folder. e.g:
app/dashboard/@analytics/loading.tsx
app/dashboard/@revenue/loading.tsx
The same is the case for error handling. Just add an error.tsx
file in each section's folder, and if something goes wrong, only that section will show an error while the rest of the page continues working.
2. Conditional Rendering
It's up to you what you do with the props sent to the layout.tsx
file - you don't have to display them. Instead, you may want to show different sections based on conditions. For example, show an admin panel only if the user is an admin, or a log in screen if the user is not logged in:
export default function Layout({ admin, user }) {
const isAdmin = checkIfUserIsAdmin();
return isAdmin ? admin : user;
}
3. Creating Modals
You can also make pop-up windows that can be bookmarked and shared, and maintain their state when refreshed.
app/
├── layout.tsx
├── page.tsx
└── @auth/
├── default.tsx (Shows nothing)
└── (.)login/
└── page.tsx (Shows login modal)
The modal becomes a real route in your application while maintaining the user experience of a traditional modal.
Navigating with Parallel Routes
Things start to get a little more complicated when you start navigating beyond your initial page in to child pages of your content. By default, NextJS will look for a similar child page in your slot.
So, for example, if you had a page at dashboard/settings
, NextJS would look for a @analytics/settings
too instead of using the original component.
There are a couple of ways to resolve this - the first is by creating a default.tsx
page to show a fallback. However, this starts to cause complications with your state when you are changing between server (when a user initially lands on your page) and client (when a user navigates to your page) side rendering.
A safer bet is to create a catch all folder using the same mechanic you'd use to create a NextJS slug - for example, [...catch]/page.tsx
. This will catch any pages that do not exist and serve this page instead.
Why Parallel Routes Are Awesome
- They make complex layouts simpler
- Each section can have its own loading state and error handling
- You can stream content as it becomes ready
- Perfect for conditional content (like showing different things to logged-in users)
- They work great with tabs, modals, and multi-section pages
- Makes your code more organized by keeping related features together
Next time you need to build a dashboard or any page with multiple independent sections, give Parallel Routes a try! It's your new superpower for website routing!
Related Blog Posts
Creating a List of Posts in Assemble
In the previous post, I showed how to get started with Assemble. Now we have content, let's look at how we can create a list of posts.
Getting Started With Assemble
Want to create a static site blog with Assemble? You've come to the right place. This in-depth tutorial will get you started with creating a blog in Assemble!
Shrinkwrap Your Dependencies
Front end development has evolved over the last couple of years thanks to `npm` popularised by task runners such as Grunt and Gulp.