← Back to chapters
14advanced

Advanced Patterns

Parallel routes, intercepting routes, streaming with Suspense, and partial prerendering.

Parallel Routes

Parallel routes let you render multiple pages in the same layout simultaneously. Think: a dashboard with independently loading panels, or a modal that overlays the page.

Parallel route structure
text
1// Folder structure for parallel routes:
2src/app/
3└── dashboard/
4 ├── layout.tsx
5 ├── page.tsx
6 ├── @analytics/
7 │ └── page.tsx ← Renders in "analytics" slot
8 ├── @notifications/
9 │ └── page.tsx ← Renders in "notifications" slot
10 └── @team/
11 └── page.tsx ← Renders in "team" slot
src/app/dashboard/layout.tsx
tsx
1// src/app/dashboard/layout.tsx
2export default function DashboardLayout({
3children,
4analytics,
5notifications,
6team,
7}: {
8children: React.ReactNode;
9analytics: React.ReactNode;
10notifications: React.ReactNode;
11team: React.ReactNode;
12}) {
13return (
14 <div className="grid grid-cols-3 gap-4">
15 <div className="col-span-2">{children}</div>
16 <aside>
17 {analytics}
18 {notifications}
19 {team}
20 </aside>
21 </div>
22);
23}
💡

Why parallel routes?

Each slot loads independently. If @analytics is slow, it doesn't block @notifications. Each can have its own loading.tsx and error.tsx. They also enable modals that work with the URL (intercepting routes).

Intercepting Routes

Intercepting routes let you show a route as a modal on the current page, while keeping the full page accessible via direct URL. Instagram-style photo modals:

Intercepting route structure
text
1src/app/
2├── feed/
3│ ├── page.tsx ← Feed page
4│ └── (..)photo/[id]/
5│ └── page.tsx ← Shows photo as MODAL on feed
6└── photo/[id]/
7 └── page.tsx ← Full photo page (direct URL)

Convention: (.) intercepts same level, (..) one level up, (..)(..) two levels up, (...) from root.

Partial Prerendering (Experimental)

PPR combines static and dynamic rendering in a single route. The static shell is served instantly from CDN, then dynamic parts stream in. It's the future of Next.js rendering.

next.config.ts
tsx
1// next.config.ts
2import type { NextConfig } from "next";
3
4const nextConfig: NextConfig = {
5experimental: {
6 ppr: true, // Enable Partial Prerendering
7},
8};
9
10export default nextConfig;
src/app/product/page.tsx
tsx
1import { Suspense } from "react";
2
3// Static shell (pre-rendered at build time)
4export default function ProductPage() {
5return (
6 <div>
7 <h1>Product Details</h1> {/* Static */}
8 <ProductInfo /> {/* Static */}
9
10 <Suspense fallback={<p>Loading price...</p>}>
11 <DynamicPrice /> {/* Dynamic, streams in */}
12 </Suspense>
13
14 <Suspense fallback={<p>Loading reviews...</p>}>
15 <Reviews /> {/* Dynamic, streams in */}
16 </Suspense>
17 </div>
18);
19}
🚀

This is where Next.js is heading

PPR gives you the speed of static sites with the flexibility of dynamic rendering. Static parts load in <50ms from CDN, dynamic parts stream in as they're ready. Best of both worlds.

Watch and Learn