0Pricing
Next.js 15 Fullstack (App Router + Server Actions) · レッスン

名前付きスロットとデフォルトセグメントによる並列ルート

@slot規約とdefault.tsxを使い、複数の独立したルートツリーを同時にレンダリングします。

「名前付きスロットとデフォルトセグメントによる並列ルート」はCoddyKit上の無料Next.js 15 Fullstack (App Router + Server Actions)レッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはNext.js 15 Fullstack (App Router + Server Actions)学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Next.js 15 Fullstack (App Router + Server Actions)コースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

What Are Parallel Routes?

Parallel Routes is a Next.js App Router feature that lets you render multiple independent route segments simultaneously inside a single layout. Each segment lives in its own named slot and can navigate, load, and error independently.

  • Think of a dashboard with a sidebar, a main panel, and a notification feed — all loaded in parallel, each with its own loading/error states.
  • Parallel routes are defined using the @folder naming convention inside a route segment directory.
  • Each slot becomes a prop on the parent layout.tsx.

This is fundamentally different from nested layouts: parallel slots share the same URL but render separate route trees side by side.

The @slot Convention

To create a parallel slot, prefix a folder with @ inside any route segment. Next.js treats these as named slots rather than URL segments.

  • app/dashboard/@analytics/page.tsx → slot named analytics
  • app/dashboard/@team/page.tsx → slot named team
  • The @folder name does not appear in the URL — visiting /dashboard renders all matching slots.

A typical parallel-routes directory tree looks like this:

// Directory layout (not runnable — filesystem structure)
// app/
//   dashboard/
//     layout.tsx          <- receives @analytics and @team as props
//     page.tsx            <- default slot content (children)
//     @analytics/
//       page.tsx
//       loading.tsx
//     @team/
//       page.tsx
//       error.tsx

Writing the Parallel Layout

The parent layout.tsx receives each named slot as a React prop alongside the standard children prop. You can position them anywhere in the JSX.

  • TypeScript types for slots are just React.ReactNode.
  • Slots are completely independent — one can suspend while another is already rendered.
  • The children prop itself is an implicit slot named children.
// app/dashboard/layout.tsx
import React from 'react';

interface DashboardLayoutProps {
  children: React.ReactNode;
  analytics: React.ReactNode;
  team: React.ReactNode;
}

export default function DashboardLayout({
  children,
  analytics,
  team,
}: DashboardLayoutProps) {
  return (
    <div className="dashboard-grid">
      <main className="col-span-2">{children}</main>
      <aside className="analytics-panel">{analytics}</aside>
      <aside className="team-panel">{team}</aside>
    </div>
  );
}

Creating Slot Pages

Each named slot needs its own page.tsx. These pages are standard Server Components (or Client Components) — there is nothing special about their internal structure.

  • Slots can have their own loading.tsx, error.tsx, and nested routes.
  • Data fetching inside a slot is independent: one slot can await a slow database call without blocking the others.
// app/dashboard/@analytics/page.tsx
import { getAnalyticsSummary } from '@/lib/analytics';

export default async function AnalyticsSlot() {
  const summary = await getAnalyticsSummary();

  return (
    <section>
      <h2 className="text-lg font-semibold">Analytics</h2>
      <p>Total visits: <strong>{summary.totalVisits}</strong></p>
      <p>Conversion rate: <strong>{summary.conversionRate}%</strong></p>
    </section>
  );
}

// app/dashboard/@team/page.tsx
import { getTeamMembers } from '@/lib/team';

export default async function TeamSlot() {
  const members = await getTeamMembers();

  return (
    <ul>
      {members.map((m) => (
        <li key={m.id}>{m.name} — {m.role}</li>
      ))}
    </ul>
  );
}

Independent Loading States

Each slot can ship its own loading.tsx. Next.js wraps it in a Suspense boundary automatically, so slots stream in independently — fast slots appear immediately while slow ones show a skeleton.

  • This eliminates the waterfall problem common in single-tree layouts.
  • Users see meaningful UI much sooner because partial content renders first.
// app/dashboard/@analytics/loading.tsx
export default function AnalyticsLoading() {
  return (
    <div className="animate-pulse space-y-2">
      <div className="h-4 bg-gray-200 rounded w-1/2" />
      <div className="h-4 bg-gray-200 rounded w-3/4" />
      <div className="h-4 bg-gray-200 rounded w-2/3" />
    </div>
  );
}

// app/dashboard/@team/loading.tsx
export default function TeamLoading() {
  return (
    <ul className="space-y-2">
      {Array.from({ length: 4 }).map((_, i) => (
        <li key={i} className="h-4 bg-gray-200 rounded animate-pulse" />
      ))}
    </ul>
  );
}

The Problem: Soft Navigation and Missing Slots

Parallel routes shine during hard navigation (full page load), but soft navigation (client-side link clicks) reveals a problem.

When a user navigates to a sub-route — for example /dashboard/settings — Next.js looks for a matching page in every active slot. If a slot has no page for /settings, it becomes unmatched.

  • An unmatched slot does not simply disappear — Next.js needs to know what to render.
  • Without a fallback, Next.js renders a 404 for the entire page.
  • The solution is default.tsx.

Rescuing Unmatched Slots with default.tsx

default.tsx is the fallback file Next.js renders for a slot when it has no matching page.tsx for the current URL. It acts like a catch-all within the slot's subtree.

  • Place default.tsx at the root of each slot: @analytics/default.tsx.
  • During soft navigation to an unmatched sub-route, Next.js renders default.tsx instead of 404-ing.
  • default.tsx receives the same params as a page; you can use it to show the slot's normal content unchanged, or a meaningful placeholder.
// app/dashboard/@analytics/default.tsx
// Rendered when the current URL has no matching page in this slot.
import { getAnalyticsSummary } from '@/lib/analytics';

export default async function AnalyticsDefault() {
  // Reuse the same data as the main analytics page so the slot
  // stays visible during navigation to other sub-routes.
  const summary = await getAnalyticsSummary();

  return (
    <section>
      <h2 className="text-lg font-semibold">Analytics</h2>
      <p>Total visits: <strong>{summary.totalVisits}</strong></p>
    </section>
  );
}

default.tsx for the Root children Slot

The implicit children slot (i.e. page.tsx at the segment root) also needs a default.tsx when parallel slots are present. Without it, navigating to a named slot's sub-route that doesn't match children will 404.

  • Add app/dashboard/default.tsx alongside app/dashboard/page.tsx.
  • It typically re-renders the same content as page.tsx, or a neutral empty state.
// app/dashboard/default.tsx
// Fallback for the implicit 'children' slot during soft navigation.
export default function DashboardDefault() {
  return (
    <div>
      <h1 className="text-2xl font-bold">Dashboard</h1>
      <p className="text-gray-500">Select an item to get started.</p>
    </div>
  );
}

Nested Routes Inside Slots

Named slots support their own nested route hierarchies. You can add [id] dynamic segments, route groups, or additional layouts entirely inside a slot — all without affecting the URL segments of sibling slots.

  • Example: @analytics/chart/[chartId]/page.tsx renders at /dashboard/chart/42 only inside the analytics slot.
  • The parent layout and other slots remain untouched.
  • Each nested level inside a slot can have its own loading.tsx, error.tsx, and default.tsx.
// app/dashboard/@analytics/chart/[chartId]/page.tsx
interface Props {
  params: Promise<{ chartId: string }>;
}

export default async function ChartDetailPage({ params }: Props) {
  const { chartId } = await params;

  // In a real app, fetch chart data here
  return (
    <div>
      <h3>Chart #{chartId}</h3>
      <p>Detailed breakdown for chart {chartId}.</p>
    </div>
  );
}

// app/dashboard/@analytics/chart/[chartId]/default.tsx
export default function ChartDefault() {
  return <p className="text-sm text-gray-400">No chart selected.</p>;
}

Practical Pattern: Modal Alongside Page

A classic use-case for parallel routes is rendering a modal in one slot while the main content stays visible in another — without losing the current scroll position or unmounting components.

  • Create an @modal slot with a default.tsx that returns null (nothing visible by default).
  • When a user clicks a trigger, Next.js navigates to the modal's page, filling the slot.
  • The main children slot continues rendering unchanged.
// app/dashboard/@modal/default.tsx
// Renders nothing when no modal route is matched.
export default function ModalDefault() {
  return null;
}

// app/dashboard/@modal/user/[id]/page.tsx
interface Props {
  params: Promise<{ id: string }>;
}

export default async function UserModal({ params }: Props) {
  const { id } = await params;
  return (
    <div className="fixed inset-0 bg-black/50 flex items-center justify-center">
      <div className="bg-white rounded-lg p-6 w-96">
        <h2 className="text-xl font-bold">User #{id}</h2>
        <p>Profile details would appear here.</p>
      </div>
    </div>
  );
}

TypeScript Tip: Strongly-Typed Slot Props

As the number of slots grows, keep your layout props explicit with a dedicated TypeScript interface. This makes refactoring safer and IDE autocompletion more helpful.

  • Slot props are always React.ReactNode — they accept any renderable value Next.js injects.
  • You can combine parallel slots with searchParams or route params in the same layout signature.
  • For shared slot configuration (e.g. theming), pass context via a React Context Provider inside the layout rather than prop-drilling through each slot page.
// app/dashboard/layout.tsx — full typed version
import React from 'react';
import { DashboardNav } from '@/components/DashboardNav';

interface DashboardLayoutProps {
  children: React.ReactNode;   // implicit slot
  analytics: React.ReactNode;  // @analytics slot
  team: React.ReactNode;       // @team slot
  modal: React.ReactNode;      // @modal slot
  params: Promise<{ orgId: string }>;
}

export default async function DashboardLayout({
  children,
  analytics,
  team,
  modal,
  params,
}: DashboardLayoutProps) {
  const { orgId } = await params;

  return (
    <>
      <DashboardNav orgId={orgId} />
      <div className="grid grid-cols-3 gap-4 p-4">
        <div className="col-span-2">{children}</div>
        <div className="space-y-4">
          {analytics}
          {team}
        </div>
      </div>
      {modal}
    </>
  );
}

Knowledge Check: When Is default.tsx Required?

Test your understanding of the default.tsx file in parallel routes.

Recap: Parallel Routes with Named Slots and Default Segments

Here is what you learned in this lesson:

  • Parallel Routes let you render multiple independent route trees in the same layout simultaneously, each in its own @slot folder.
  • Named slots use the @folderName convention and become props (React.ReactNode) on the parent layout.tsx.
  • Each slot is truly independent: it can have its own loading.tsx, error.tsx, nested routes, and data fetching without blocking siblings.
  • default.tsx is the critical fallback file. Without it, soft navigation to a URL that does not match a slot produces a 404. Place a default.tsx in every slot — including the implicit children slot — to prevent this.
  • Common patterns include dashboard multi-panels (analytics + team side by side) and modal-alongside-page where the @modal slot's default.tsx returns null.
  • Keep layout props strongly typed with a TypeScript interface as the slot count grows.

With parallel routes and default.tsx in place, your layouts become resilient, independently streaming, and far easier to reason about than a single monolithic route tree.

よくある質問

「名前付きスロットとデフォルトセグメントによる並列ルート」レッスンは無料ですか?

はい。「名前付きスロットとデフォルトセグメントによる並列ルート」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Next.js 15 Fullstack (App Router + Server Actions)コースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Next.js 15 Fullstack (App Router + Server Actions)コースには全4レッスンが含まれています。

「名前付きスロットとデフォルトセグメントによる並列ルート」で何を学びますか?

@slot規約とdefault.tsxを使い、複数の独立したルートツリーを同時にレンダリングします。 ブラウザで直接実行するハンズオンコードでNext.js 15 Fullstack (App Router + Server Actions)を演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Next.js 15 Fullstack (App Router + Server Actions)を始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのNext.js 15 Fullstack (App Router + Server Actions)は初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「名前付きスロットとデフォルトセグメントによる並列ルート」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このNext.js 15 Fullstack (App Router + Server Actions)レッスンでコードを書いて実行できますか?

はい。すべてのNext.js 15 Fullstack (App Router + Server Actions)レッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 名前付きスロットとデフォルトセグメントによる並列ルート
  2. 共有モーダル体験のためのインターセプトルート
  3. ダッシュボードとタブの条件付きスロットレンダリング
  4. ソフトナビゲーションによる写真モーダルフローの構築
← Next.js 15 Fullstack (App Router + Server Actions)に戻る