Parallel Routes

Slots

A folder named @something is a slot. The parent layout receives each slot as a prop and can render several pages at the same time, each with its own loading and error state. Slots are not part of the URL.

app/admin/
├── layout.tsx           receives children, revenue, orders
├── page.tsx             -> children
├── @revenue/
│   ├── page.tsx         revenue chart
│   └── loading.tsx
└── @orders/
    ├── page.tsx         latest orders
    └── error.tsx
// app/admin/layout.tsx
export default function AdminLayout({
  children,
  revenue,
  orders,
}: {
  children: React.ReactNode;
  revenue: React.ReactNode;
  orders: React.ReactNode;
}) {
  return (
    <div className="grid gap-6 lg:grid-cols-2">
      <div className="lg:col-span-2">{children}</div>
      {revenue}
      {orders}
    </div>
  );
}

default.tsx

When you navigate to a sub-URL that a slot does not have, Next.js needs to know what to render in that slot. On a full page load, it renders the slot's default.tsx (or 404 if there is none). Usually return null:

// app/admin/@orders/default.tsx
export default function Default() {
  return null;
}

Conditional Slots

// show a different dashboard per role
import { auth } from '@/auth';

export default async function Layout({ admin, seller }: { admin: React.ReactNode; seller: React.ReactNode }) {
  const session = await auth();
  return <>{session?.user.role === 'admin' ? admin : seller}</>;
}