Parallel routes
This page explains how to implement parallel routes in Next.js to render multiple pages simultaneously within the same layout.
What are parallel routes?
Parallel routes is an advanced routing mechanism that allows you to render multiple pages simultaneously within the same layout. It is useful for building complex user interfaces that need to display multiple independent sections.
Creating parallel routes
Parallel routes use slots, created using the @folder
naming convention. Each slot becomes a prop in the corresponding layout file. Consider a dashboard with three independent sections: analytics, revenue, and notifications:
Directoryapp/
Directorydashboard/
Directory@analytics/
- page.tsx
Directory@revenue/
- page.tsx
Directory@notifications/
- page.tsx
- layout.tsx
- page.tsx
Create the slot components:
// app/dashboard/@analytics/page.tsxexport default function Analytics() { return <div>Analytics content</div>;}
// app/dashboard/@revenue/page.tsxexport default function Revenue() { return <div>Revenue metrics</div>;}
// app/dashboard/@notifications/page.tsxexport default function Notifications() { return <div>Latest notifications</div>;}
The layout receives each slot as a prop:
export default function DashboardLayout({ children, analytics, revenue, notifications,}: { children: React.ReactNode; analytics: React.ReactNode; revenue: React.ReactNode; notifications: React.ReactNode;}) { return ( <div> <div>{children}</div> <div style={{ display: "flex" }}> <div>{analytics}</div> <div>{revenue}</div> <div>{notifications}</div> </div> </div> );}
Visit /dashboard
to see the parallel routes in action. All three sections are rendered simultaneously.
Benefits of parallel routes
You might be wondering why you should use parallel routes when you can use a single layout file and render the sections in the same component. There are two main benefits:
Independent route handling
Parallel routes enable independent handling of each route. Each slot in your layout can manage its own loading and error states. This granular control is valuable when different sections load at varying speeds or encounter errors.
// app/dashboard/@analytics/loading.tsxexport default function AnalyticsLoading() { return <div>Loading analytics...</div>;}
// app/dashboard/@revenue/error.tsx"use client";
export default function RevenueErrorBoundary({ error, reset,}: { error: Error; reset: () => void;}) { return ( <div> <p>Error loading revenue metrics: {error.message}</p> <button onClick={reset}>Retry</button> </div> );}
For example, if the user analytics data is loading, you can display a loading spinner for that section while keeping other sections interactive. If revenue metrics fail to load, you can show an error message in that specific slot without affecting the rest of the dashboard.
Sub-navigation capabilities
Parallel routes support seamless sub-navigation within each route. Each slot functions as a mini-application with independent navigation and state management. Users can interact with each section separately — applying filters, sorting data, or navigating through pages — without affecting other sections.
For instance, the notifications section can switch between default and archived views. These interactions remain contained within the notifications section, and the URL updates accordingly. This makes the URL shareable and helps users track their location in the application.
Good to know
- Slots are not route segments and don’t affect the URL structure
- The children prop is an implicit slot -
dashboard/page.tsx
is equivalent todashboard/@children/page.tsx
- Each slot can have its own loading and error states
- Slots enable independent navigation within each section
- Common use cases include dashboards, split views, and admin interfaces