Skip to content
Watch the complete Next.js 15 course on YouTube

Intercepting routes

This page explains how to implement route interception in Next.js to load content from another route while preserving the current context.

Understanding intercepting routes

Intercepting routes allows you to show content from a different route while maintaining the current layout and UI state. This pattern enables advanced UX patterns like modal overlays that:

  • Preserve the current page context
  • Update the URL to match the intercepted content
  • Maintain a shareable/bookmarkable URL
  • Work correctly on page refresh

Intercepting routes conventions

Next.js provides special naming conventions for route interception:

  • (.) - Match segments at same level
  • (..) - Match segments one level above
  • (..)(..) - Match segments two levels above
  • (...) - Match segments from root

Same level (.)

Suppose we have the following file structure and we want to intercept the route /f1/f2 from /f1:

  • Directoryapp/
    • Directoryf1/ source route
      • page.tsx
      • Directoryf2/ target route
        • page.tsx
  1. Start in your source route directory app/f1/ and create a new folder that will contain your intercepting page: app/f1/prefix_intercepting-folder/page.tsx
  2. Name the folder the same as the target route f2: app/f1/prefix_f2/page.tsx
  3. Add the prefix (.) since f2 and prefix_f2 are at the same level: app/f1/(.)f2/page.tsx
  • Directoryapp/
    • Directoryf1/ source route
      • page.tsx
      • Directory(.)f2/ intercepting route
        • page.tsx
      • Directoryf2/ target route
        • page.tsx
app/f1/page.tsx
import Link from "next/link";
export default function F1() {
return (
<>
<h1>F1 page</h1>
<Link href="/f1/f2">Go to F2</Link>
</>
);
}
app/f1/f2/page.tsx
export default function F2() {
return <h1>F2 page</h1>;
}
// Interceptor: app/f1/(.)f2/page.tsx
export default function InterceptedF2() {
return <h1>(.) Intercepted F2 page</h1>;
}

When a user clicks a link to /f1/f2 from the /f1 page:

  1. The URL changes to /f1/f2
  2. The (.)f2 intercepting route is shown to the user
  3. On page refresh, the actual f2 route is shown instead

One level up (..)

Suppose we have the following file structure and we want to intercept the route /f3 from /f1:

  • Directoryapp/
    • Directoryf1/ source route
      • page.tsx
    • Directoryf3/ target route
      • page.tsx
  1. Start in your source route directory app/f1/ and create a new folder that will contain your intercepting page: app/f1/prefix_intercepting-folder/page.tsx
  2. Name the folder the same as the target route f3: app/f1/prefix_f3/page.tsx
  3. Add the prefix (..) since f3 is one level up from f1: app/f1/(..)f3/page.tsx
  • Directoryapp/
    • Directoryf1/ source route
      • page.tsx
      • Directory(..)f3/ intercepting route
        • page.tsx
    • Directoryf3/ target route
      • page.tsx
app/f1/page.tsx
import Link from "next/link";
export default function F1() {
return (
<>
<h1>F1 page</h1>
<Link href="/f3">Go to F3</Link>
</>
);
}
app/f3/page.tsx
export default function F3() {
return <h1>F3 page</h1>;
}
// Interceptor: app/f1/(..)f3/page.tsx
export default function InterceptedF3() {
return <h1>(..) Intercepted F3 page</h1>;
}

When a user clicks a link to /f3 from the /f1 page:

  1. The URL changes to /f3
  2. The (..)f3 intercepting route is shown to the user
  3. On page refresh, the actual f3 route is shown instead

Two levels up (..)(..)

Suppose we have the following file structure and we want to intercept the route /f4 from /f1/f2:

  • Directoryapp/
    • Directoryf1/
      • Directoryf2/ source route
        • page.tsx
    • Directoryf4/ target route
      • page.tsx
  1. Start in your source route directory app/f1/f2/ and create a new folder that will contain your intercepting page: app/f1/f2/prefix_intercepting-folder/page.tsx
  2. Name the folder the same as the target route f4: app/f1/f2/prefix_f4/page.tsx
  3. Add the prefix (..)(..) since f4 is two levels up from f2: app/f1/f2/(..)(..)f4/page.tsx
  • Directoryapp/
    • Directoryf1/
      • Directoryf2/ source route
        • page.tsx
        • Directory(..)(..)f4/ intercepting route
          • page.tsx
    • Directoryf4/ target route
      • page.tsx
app/f1/f2/page.tsx
import Link from "next/link";
export default function F2() {
return (
<>
<h1>F2 page</h1>
<Link href="/f4">Go to F4</Link>
</>
);
}
app/f4/page.tsx
export default function F4() {
return <h1>F4 page</h1>;
}
// Interceptor: app/f1/f2/(..)(..)f4/page.tsx
export default function InterceptedF4() {
return <h1>(..)(..) Intercepted F4 page</h1>;
}

When a user clicks a link to /f4 from the /f1/f2 page:

  1. The URL changes to /f4
  2. The (..)(..)f4 intercepting route is shown to the user
  3. On page refresh, the actual f4 route is shown instead

Root level (…)

Suppose we have the following file structure and we want to intercept the route /f5 from /f1/f2/inner-f2:

  • Directoryapp/
    • Directoryf1/
      • Directoryf2/
        • Directoryinner-f2/ source route
          • page.tsx
    • Directoryf5/ target route
      • page.tsx
  1. Start in your source route directory app/f1/f2/inner-f2/ and create a new folder that will contain your intercepting page: app/f1/f2/inner-f2/prefix_intercepting-folder/page.tsx
  2. Name the folder the same as the target route f5: app/f1/f2/inner-f2/prefix_f5/page.tsx
  3. Add the prefix (...) to match from root: app/f1/f2/inner-f2/(...)f5/page.tsx
  • Directoryapp/
    • Directoryf1/
      • Directoryf2/
        • Directoryinner-f2/ source route
          • page.tsx
          • Directory(…)f5/ intercepting route
            • page.tsx
    • Directoryf5/ target route
      • page.tsx
app/f1/f2/inner-f2/page.tsx
import Link from "next/link";
export default function InnerF2() {
return (
<>
<h1>Inner F2 page</h1>
<Link href="/f5">Go to F5</Link>
</>
);
}
app/f5/page.tsx
export default function F5() {
return <h1>F5 page</h1>;
}
// Interceptor: app/f1/f2/inner-f2/(...)f5/page.tsx
export default function InterceptedF5() {
return <h1>(...) Intercepted F5 page</h1>;
}

When a user clicks a link to /f5 from the /f1/f2/inner-f2 page:

  1. The URL changes to /f5
  2. The (...)f5 intercepting route is shown to the user
  3. On page refresh, the actual f5 route is shown instead

File structure overview

  • Directoryapp/
    • Directoryf1/
      • Directory(.)f2/ // same level
        • page.tsx
      • Directory(..)f3/ // one level up
        • page.tsx
      • Directoryf2/
        • Directory(..)(..)f4/ // two levels up
          • page.tsx
        • Directoryinner-f2/
          • page.tsx
          • Directory(…)f5/ // root level
            • page.tsx
    • Directoryf3/
      • page.tsx
    • Directoryf4/
      • page.tsx
    • Directoryf5/
      • page.tsx

This structure shows how: (.) matches at the same level (f1 → f2) (..) matches one level up (f1 → f3) (..)(..) matches two levels up (f2 → f4) (…) matches from root (inner-f2 → f5) Each prefix is determined by the relationship between the source route (where the link is) and the target route (where we’re navigating to).

Common use cases

Route interception is particularly useful for:

  • Photo/video modals in galleries
  • Authentication flows
  • Product quick-views in e-commerce
  • Expanded post views in social feeds

Good to know

  • Intercepted routes maintain shareable URLs
  • Original layout/context is preserved
  • Works with browser back/forward navigation