Параллельные маршруты с именованными слотами и сегментами по умолчанию
Одновременно отображайте несколько независимых деревьев маршрутов, используя соглашения @slot и default.tsx.
«Параллельные маршруты с именованными слотами и сегментами по умолчанию» — бесплатный урок Next.js 15 Fullstack (App Router + Server Actions) на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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
@foldernaming 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 namedanalyticsapp/dashboard/@team/page.tsx→ slot namedteam- The
@foldername does not appear in the URL — visiting/dashboardrenders 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.tsxWriting 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
childrenprop itself is an implicit slot namedchildren.
// 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
awaita 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.tsxat the root of each slot:@analytics/default.tsx. - During soft navigation to an unmatched sub-route, Next.js renders
default.tsxinstead of 404-ing. default.tsxreceives 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.tsxalongsideapp/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.tsxrenders at/dashboard/chart/42only 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, anddefault.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
@modalslot with adefault.tsxthat returnsnull(nothing visible by default). - When a user clicks a trigger, Next.js navigates to the modal's page, filling the slot.
- The main
childrenslot 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
searchParamsor routeparamsin 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
@slotfolder. - Named slots use the
@folderNameconvention and become props (React.ReactNode) on the parentlayout.tsx. - Each slot is truly independent: it can have its own
loading.tsx,error.tsx, nested routes, and data fetching without blocking siblings. default.tsxis the critical fallback file. Without it, soft navigation to a URL that does not match a slot produces a 404. Place adefault.tsxin every slot — including the implicitchildrenslot — to prevent this.- Common patterns include dashboard multi-panels (analytics + team side by side) and modal-alongside-page where the
@modalslot'sdefault.tsxreturnsnull. - 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/7) и разблокировать остальной курс 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/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Next.js 15 Fullstack (App Router + Server Actions)?
Предыдущий опыт не требуется. Next.js 15 Fullstack (App Router + Server Actions) на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Параллельные маршруты с именованными слотами и сегментами по умолчанию»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Next.js 15 Fullstack (App Router + Server Actions)?
Да. Каждый урок Next.js 15 Fullstack (App Router + Server Actions) включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Параллельные маршруты с именованными слотами и сегментами по умолчанию
- Перехватывающие маршруты для общих сценариев с модальными окнами
- Условное отображение слотов для панелей и вкладок
- Создание сценария фото-модального окна с мягкой навигацией