Pages And Layouts
Pages and Layouts
Pages are your route components. Layouts wrap pages with shared UI. This guide explains how they work together.
Pages
A page is a React component exported from web/pages/:
// web/pages/about.tsx
export default function About() {
return (
<div>
<h1>About Us</h1>
<p>This is the about page.</p>
</div>
)
}Page Metadata
Export metadata to customize the page:
export const metadata = {
title: "About Us - My Site",
description: "Learn more about our company.",
}Layouts
Layouts wrap pages with shared UI (navigation, sidebars, footers).
Global Layout
Create web/layouts/global.tsx to wrap all pages across your application:
// web/layouts/global.tsx
export default function GlobalLayout({ children }: { children: React.ReactNode }) {
return (
<div className="app-shell">
<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>{children}</main>
<footer>© 2026 My Site</footer>
</div>
)
}The global layout is passed directly to <FileRouter GlobalLayout={GlobalLayout} /> in your app bootstrap (core/bootstrap/web.tsx).
Named Layouts
Create reusable named layouts in web/layouts/:
web/layouts/
├─ global.tsx # Wraps all pages
├─ dashboard.tsx # Dashboard layout
└─ auth.tsx # Auth layoutDefine the layout component (e.g. web/layouts/dashboard.tsx):
// web/layouts/dashboard.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="dashboard-layout flex">
<aside className="w-64 border-r">Sidebar</aside>
<section className="flex-1 p-6">{children}</section>
</div>
)
}Applying a Layout to a Page
To apply a named layout to a page, export layout with the layout's file name:
// web/pages/dashboard.tsx
export const metadata = { title: "Dashboard" }
// Selects web/layouts/dashboard.tsx
export const layout = "dashboard"
export default function DashboardPage() {
return <h1>Welcome to Dashboard</h1>
}Layout Hierarchy
When a page declares a layout, Dex composes them in order:
- GlobalLayout (from
web/layouts/global.tsx) - Page-declared Layout (e.g.
web/layouts/dashboard.tsx) - Page Component (from
web/pages/dashboard.tsx)
Rendered output:
<div class="app-shell">
<div class="dashboard-layout">
<aside>Sidebar</aside>
<section>
<h1>Welcome to Dashboard</h1>
</section>
</div>
</div>Nested Layouts
For nested routes, layouts nest naturally:
web/pages/
├─ blog/
│ ├─ index.tsx # Uses blog.tsx layout
│ └─ posts/
│ ├─ index.tsx # Uses blog.tsx + posts.tsx layout
│ └─ [slug].tsx # Uses blog.tsx + posts.tsx layoutData in Layouts
Layouts can fetch data just like pages:
// web/layouts/blog.tsx
import { useServerData } from '@dex/server'
export default function BlogLayout({ children }) {
const { posts } = useServerData()
return (
<div>
<aside>
{posts.map(p => <a key={p.id}>{p.title}</a>)}
</aside>
{children}
</div>
)
}Best Practices
- Keep global layout minimal — only essential elements
- Use section layouts — for repeated section-specific UI
- Avoid page-level layouts — prefer reusable section layouts
- Metadata in pages — not layouts, for better control
See Also
- File-Based Routing — How pages map to routes
- Configuration — Customize layout folder
- How Dex Works — Build process overview