WritingNext.js Parallel Routes and Intercepting Routes: A Practical Guide — Clixo
5 min readnext.js, routing, parallel-routes, advanced, app-router

Next.js Parallel Routes and Intercepting Routes: A Practical Guide

How to use Next.js parallel routes and intercepting routes to build URL-driven modals, split dashboards, and complex layouts that survive refresh and deep linking.

Most teams discover parallel routes and intercepting routes when they try to build something that should be simple — a photo gallery where clicking an image opens a modal, but the URL changes so the modal is shareable and survives a browser refresh. With a traditional modal approach, the page state is lost on refresh. With a separate route, the modal context is lost when you navigate away. Parallel and intercepting routes exist precisely to solve this.

This guide explains what these routing primitives are, how they work together, and when to reach for them.

What Are Parallel Routes?

Parallel routes let a single layout render two or more route segments simultaneously in named slots. The layout defines the slots; child routes fill them independently.

Slots are defined using the @folder convention. A folder named @analytics in your route directory becomes an analytics prop passed to the layout.

app/
  dashboard/
    layout.tsx          ← receives { children, analytics, team }
    @analytics/
      page.tsx          ← renders in the analytics slot
    @team/
      page.tsx          ← renders in the team slot
    page.tsx            ← renders in children

In layout.tsx, each slot is a component prop:

export default function DashboardLayout({
  children,
  analytics,
  team,
}: {
  children: React.ReactNode
  analytics: React.ReactNode
  team: React.ReactNode
}) {
  return (
    <div className="grid grid-cols-2">
      <main>{children}</main>
      <aside>
        {analytics}
        {team}
      </aside>
    </div>
  )
}

Each slot fetches its own data, has its own loading and error states, and can navigate independently. A loading delay in the analytics slot does not block the team slot. This is more composable than building everything into a single page component.

What Are Intercepting Routes?

Intercepting routes let you render a route within the context of another route. When you navigate client-side (by clicking a link), the intercepting route shows. When you navigate directly via URL or refresh the page, the real route shows.

The syntax uses relative-path indicators wrapped in parentheses:

  • (.)slug — intercepts a sibling route
  • (..)slug — intercepts a route one level up
  • (..)(..)slug — intercepts a route two levels up
  • (...)slug — intercepts from the app root

Example: In a photo gallery at /photos, you want clicking a photo to show a modal at /photos/42, but navigating directly to /photos/42 should show the full photo page.

app/
  photos/
    page.tsx                ← gallery grid
    [id]/
      page.tsx              ← full photo page (direct URL or refresh)
    @modal/
      (.)photos/[id]/
        page.tsx            ← intercepted route (shows as modal)
      default.tsx           ← renders null when no modal is active
    layout.tsx              ← renders {children} and {modal}

When a user clicks a photo thumbnail, Next.js detects the client-side navigation and renders the intercepted (.)photos/[id]/page.tsx in the @modal slot. The gallery remains visible in the background. The URL changes to /photos/42. If the user copies that URL and opens it in a new tab, the interception does not apply — they see the full [id]/page.tsx instead.

The Modal Pattern in Practice

This combination — parallel routes plus intercepting routes — solves the classic modal problem with properties that are otherwise hard to achieve simultaneously:

  • Shareable URL. The modal has a real URL that can be copied and sent.
  • Deep linking. Opening the URL directly shows the full page, not a broken modal state.
  • Browser history. Back and forward buttons work correctly.
  • Background context. The page behind the modal remains visible and scrollable.
  • Refresh safety. Refreshing the page in modal state shows the full route instead of crashing.

These properties come for free from the routing model — no JavaScript state management required.

Handling the Default State

Slots require a default.tsx file to handle the case where a slot has no active match. When a user navigates directly to /photos (no photo selected), the @modal slot has nothing to render. Without default.tsx, Next.js throws an error.

// app/photos/@modal/default.tsx
export default function DefaultModal() {
  return null
}

Every slot that uses intercepting routes needs this file.

Independent Loading and Error States

Each parallel route slot can have its own loading.tsx and error.tsx. A slow analytics query does not block the team slot from rendering. An error in one slot shows a recovery UI in that slot without crashing the whole layout.

This granularity is one of the strongest arguments for using parallel routes in dashboards. Complex admin interfaces often have four or five data-heavy sections on one screen. Without parallel routes, a single slow query holds up everything. With them, each section loads and fails independently.

When to Use These Patterns

Use parallel routes when:

  • A dashboard has independently loading sections that should not block each other
  • Different segments of a layout have different loading and error states
  • Two unrelated routes need to appear on the same screen simultaneously

Use intercepting routes when:

  • You need a modal with a shareable, deep-linkable URL
  • Navigating from a list context should show a preview, but the full page should be accessible directly
  • You want browser history to work naturally through a modal flow

Avoid them when:

  • A simple client-side modal with no URL change is sufficient
  • The complexity of named slots and default files outweighs the benefit
  • The intercepted and non-intercepted experiences would be identical anyway

Parallel routes and intercepting routes are among the most powerful features in the App Router. They are also among the most underused, partly because the documentation is dense and partly because the use cases are not obvious until you run into the problem they solve.

If you're building a Next.js application with complex routing requirements and want engineering support, Clixo builds custom Next.js systems for product teams that need them to work correctly.