Wrap a folder name in parentheses: (name). The folder organizes files but does not appear in the URL.
app/
(marketing)/
layout.tsx ← marketing-specific layout
page.tsx → /
pricing/page.tsx → /pricing
blog/page.tsx → /blog
(app)/
layout.tsx ← authed layout, separate chrome
dashboard/page.tsx → /dashboard
settings/page.tsx → /settings
Use cases:
(checkout)/cart, (checkout)/payment, (checkout)/confirm.middleware.ts.Place layout.tsx directly inside each group and remove the global app/layout.tsx from a top-level role:
1// app/(marketing)/layout.tsx
2import "./globals.css";
3export default function MarketingLayout({ children }: { children: React.ReactNode }) {
4 return (
5 <html lang="en"><body className="font-sans">{children}</body></html>
6 );
7}
8
9// app/(app)/layout.tsx
10import "./globals.css";
11export default function AppLayout({ children }: { children: React.ReactNode }) {
12 return (
13 <html lang="en" className="dark"><body className="font-mono bg-gray-950 text-gray-50">{children}</body></html>
14 );
15}Each root layout must render
<html>and<body>— they are independent.
Parallel routes let one layout render multiple slots that navigate independently.
@ prefixes a parallel slot. The layout receives it as a prop.
app/dashboard/
layout.tsx
page.tsx
@analytics/page.tsx
@team/page.tsx
1// app/dashboard/layout.tsx
2export default function DashboardLayout({
3 children,
4 analytics,
5 team,
6}: {
7 children: React.ReactNode;
8 analytics: React.ReactNode;
9 team: React.ReactNode;
10}) {
11 return (
12 <div className="grid grid-cols-3 gap-4">
13 <section>{children}</section>
14 <section>{analytics}</section>
15 <section>{team}</section>
16 </div>
17 );
18}loading.tsx and error.tsx./dashboard — while slots can be navigated independently.If a slot has no matching segment for a URL, Next renders its default.tsx (or null if absent):
1// app/dashboard/@analytics/default.tsx
2export default function Default() {
3 return null; // no analytics for this URL
4}1export default async function DashboardLayout({ children, admin, user }) {
2 const me = await getSession();
3 return (
4 <>
5 {children}
6 {me?.role === "ADMIN" ? admin : user}
7 </>
8 );
9}The unused slot isn't fetched — Next code-splits per slot.
default.tsx → the slot 404s on direct URL visits.(name) with parallel routes @name — the first is organizational; the second renders multiple pages.