Parallel Routes and Intercepting Routes in Next.js Explained
Lesson 1.6 covered file-based routing's core patterns: static routes, nested routes, and route groups. This lesson introduces two considerably more advanced routing features that solve a specific, common UI challenge — the 'modal that's also a real page' pattern, seen constantly on sites like Instagram or Twitter/X, where clicking a photo opens it in a modal overlay on top of the current feed, but directly visiting or sharing that same photo's URL loads it as its own genuine, full standalone page.
Parallel routes let you render more than one independent page simultaneously within the same layout, while intercepting routes let a navigation 'intercept' what would normally be a full page transition and instead show different content, typically a modal. Combined, these two features are exactly what powers this modal-that's-also-a-real-page pattern, and this lesson covers both individually before showing how they work together.
Learning Objectives
- Create parallel routes using the @slot naming convention.
- Render multiple independent pages simultaneously within one shared layout.
- Create an intercepting route using the (.) convention to show different content for an in-app navigation.
- Combine parallel routes and intercepting routes to build a modal routing pattern.
- Understand default.tsx's role in parallel routes.
Core Definitions
- Parallel routes: A routing pattern, using folders named with an @ prefix (a 'slot'), that lets you render two or more pages simultaneously within the same layout, each independently navigable.
- Slot: An individually named parallel route folder (e.g., @analytics, @team) passed as a prop into its parent layout, which decides where and how to render it.
- default.tsx: A fallback file rendered for a parallel route slot when no more specific match exists for the current URL, preventing a 404 for that particular slot.
- Intercepting routes: A routing pattern, using folders named with (.) or (..) conventions, that lets an in-app navigation show different content than what a direct, fresh visit to that same URL would show.
- Modal routing pattern: A UI pattern where navigating within an app opens content in a modal overlay, while a direct visit or refresh loads that same content as a full standalone page.
Detailed Explanation
Parallel routes are created by naming a folder with an @ prefix — @team, @analytics — inside a shared layout's directory. Each of these '@slot' folders behaves like an independently rendered mini-application, its own page.tsx (and even its own loading.tsx and error.tsx) rendering simultaneously alongside any other slots, all passed as named props into their shared parent layout.tsx. The layout then decides exactly how to arrange these simultaneously-rendering slots: `export default function Layout({ children, team, analytics }) { return <>{children}<div className="flex">{team}{analytics}</div></> }` — note that the regular page.tsx content is still available as the standard children prop, alongside each named slot.
A practical use for parallel routes is a dashboard where a sidebar's content and a main content area need to update independently based on different, unrelated parts of the URL, or where you want two genuinely separate pieces of UI (say, a notifications panel and a settings panel) each capable of showing their own loading and error states independently, without one blocking the other. If a specific slot doesn't have a matching sub-route for the currently visited URL, a default.tsx file within that slot's folder provides fallback content, preventing an unwanted 404 for that particular slot while the rest of the page renders normally.
Intercepting routes solve a different problem: showing different content depending on HOW a user arrived at a URL. A folder named with (.) (matching a route at the same level), (..) (one level above), (..)(..) (two levels above), or (...) (from the root) tells Next.js: 'if a user navigates to this URL from within the app (via a Link click), show THIS intercepted content instead of the URL's normal page — but if a user arrives at this exact URL directly (typing it in, refreshing, or via an external link), show the normal, non-intercepted page instead.'
Combining both features is what creates the classic modal pattern: a parallel route slot (commonly named @modal) is added to a shared layout, and inside that slot, an intercepting route folder captures in-app navigations to a specific nested URL (like a photo's detail page) and renders that content as a modal, layered on top of whatever's already showing in the main content area. Meanwhile, a completely separate, regular (non-intercepted) route at that same URL path handles the case of someone directly visiting or refreshing that exact photo URL, rendering it as its own full, standalone page instead of a modal — giving both behaviors from the exact same URL, differentiated purely by how the visitor arrived there.
How Parallel Routes and Intercepting Routes Combine for a Modal Pattern
{"heading":"How Parallel Routes and Intercepting Routes Combine for a Modal Pattern","description":"Visualize the folder structure powering an Instagram-style photo modal:\n\napp/\n├── layout.tsx (renders {children} AND {modal})\n├── page.tsx (the main feed)\n├── @modal/\n│ ├── default.tsx (renders null when no modal is active)\n│ └── (.)photo/[id]/\n│ └── page.tsx (INTERCEPTED: modal version, shown for in-app clicks)\n└── photo/[id]/\n └── page.tsx (the REAL, standalone full-page version)\n\nUser clicks a photo thumbnail (in-app Link) --> intercepted @modal/(.)photo/[id] renders as an overlay, feed stays visible behind it\nUser directly visits /photo/42 or refreshes --> the REAL app/photo/[id]/page.tsx renders as its own full page, no modal"}
Next.js Practical Example
// app/layout.tsx — rendering the main content AND the @modal slot together
export default function RootLayout({
children,
modal,
}: {
children: React.ReactNode;
modal: React.ReactNode;
}) {
return (
<html>
<body>
{children}
{modal} {/* renders on top when the intercepted route is active */}
</body>
</html>
);
}
// app/@modal/default.tsx — fallback: render nothing when no modal is active
export default function Default() {
return null;
}
// app/@modal/(.)photo/[id]/page.tsx — the INTERCEPTED modal version
export default function PhotoModal({ params }: { params: { id: string } }) {
return (
<div className="modal-overlay">
<div className="modal-content">Photo #{params.id} (shown as a modal)</div>
</div>
);
}
// app/photo/[id]/page.tsx — the REAL, standalone full page
export default function PhotoPage({ params }: { params: { id: string } }) {
return <main>Photo #{params.id} (full standalone page)</main>;
}
RootLayout renders both {children} (the normal page content, like a feed) and {modal} (the @modal slot's content) simultaneously — when no photo modal is active, @modal/default.tsx renders null, so nothing extra appears. When a user clicks a photo thumbnail using an in-app Link, Next.js recognizes this as matching the intercepting route at app/@modal/(.)photo/[id]/page.tsx, rendering PhotoModal as an overlay on top of the still-visible feed underneath. If instead a user directly visits /photo/42 (typing the URL, refreshing the page, or arriving via an external link/search result), Next.js renders the completely separate app/photo/[id]/page.tsx instead — the real, full standalone page — since there was no in-app navigation to intercept in that case.
Real Products Using This Modal Routing Pattern
- Social media platforms like Instagram and Twitter/X use exactly this pattern for photo and post detail views: clicking within the app opens a modal overlay, while directly visiting or sharing that same post's URL loads a full, standalone page.
- E-commerce sites use parallel routes for dashboard-style admin panels, rendering an orders summary and an inventory summary as independent slots that can each show their own loading states without blocking one another.
- Video platforms use the intercepting route pattern for a 'quick preview' modal when clicking a video thumbnail from a browsing grid, while a direct visit to that video's URL loads the full watch page with related videos and comments.
- Project management tools use parallel routes to render a task list and a filter sidebar as genuinely independent slots, each capable of updating and showing loading states without needing to coordinate rendering with the other.
- Documentation and marketplace sites use intercepting routes for 'quick look' product or item previews triggered from a grid, while direct navigation to that specific item's URL renders the full, detailed page.
Common Mistakes to Avoid
- Forgetting to include a default.tsx in a parallel route slot, causing an unexpected 404 for that slot when no more specific match exists.
- Confusing the @slot (parallel routes) syntax with the (routeGroup) syntax from Lesson 1.6, which serve entirely different purposes.
- Expecting an intercepted modal route to also appear on a direct URL visit, without realizing that scenario correctly falls through to the separate, non-intercepted full-page route instead.
- Using the wrong level of intercepting route convention — (.), (..), (..)(..), or (...) — resulting in the interception not matching the intended navigation source.
- Overusing parallel routes for simple UI that doesn't genuinely need independent, simultaneous rendering, adding unnecessary architectural complexity.
Interview Notes
- Parallel routes use an @slot naming convention, rendering multiple independent pages simultaneously within a shared layout via named props.
- default.tsx provides fallback content for a parallel route slot when no specific match exists, avoiding an unwanted 404 for that slot.
- Intercepting routes use (.) / (..) / (..)(..) / (...) conventions to show different content for an in-app navigation versus a direct URL visit.
- Combining a @modal parallel route slot with an intercepting route inside it, alongside a separate real route at the same path, creates the modal-that's-also-a-real-page pattern.
- A direct visit or refresh always falls through to the regular, non-intercepted route, never showing the modal version.
Key Takeaways
- Parallel routes and intercepting routes are advanced, specialized tools solving specific UI challenges beyond the basic routing patterns from Lesson 1.6.
- The @slot convention enables genuinely independent, simultaneously rendering pieces of UI within one shared layout.
- Intercepting routes elegantly solve the tension between wanting a modal-style in-app experience and needing a genuine, shareable, SEO-friendly standalone page at the same URL.
- Combining these two features is the standard, well-established pattern behind the modal experiences seen across many major social and content platforms.
Summary
Parallel routes, created using an @slot naming convention (like @team or @analytics), let Next.js render multiple independent pages simultaneously within a single shared layout, each passed in as a named prop alongside the regular children content, with a default.tsx file providing fallback content when a specific slot has no matching route for the current URL. Intercepting routes, using (.) / (..) / (..)(..) / (...) folder conventions, solve a different problem: showing different content for an in-app navigation to a URL versus a direct visit to that same URL. Combining both features creates the well-known modal-that's-also-a-real-page pattern seen on platforms like Instagram: a @modal parallel route slot contains an intercepting route that renders a modal overlay for in-app clicks, while a completely separate, regular route at the same URL path renders the content as a full, standalone page for direct visits, refreshes, or shared links — giving both experiences from the exact same URL, differentiated purely by how a visitor arrived.