Layouts: Shared UI That Persists
A layout wraps your pages. Think navbar, sidebar, footer. Stuff that stays the same across multiple pages. The beautiful thing? Layouts DON'T re-render when you navigate between their child pages. They persist state.
Root Layout
Every Next.js app needs a root layout. This is the top-level wrapper for your entire app:
1// src/app/layout.tsx2import type { Metadata } from "next";34export const metadata: Metadata = {5title: "My App",6description: "Built with Next.js",7};89export default function RootLayout({10children,11}: {12children: React.ReactNode;13}) {14return (15 <html lang="en">16 <body>17 <nav>My Navbar</nav>18 {children}19 <footer>My Footer</footer>20 </body>21 </html>22);23}Important
Nested Layouts
Here's where it gets powerful. You can have layouts at ANY level. An admin section can have its own sidebar layout:
1// src/app/admin/layout.tsx2export default function AdminLayout({3children,4}: {5children: React.ReactNode;6}) {7return (8 <div className="flex">9 <aside className="w-64 bg-gray-900 text-white min-h-screen p-4">10 <nav>11 <a href="/admin">Dashboard</a>12 <a href="/admin/users">Users</a>13 <a href="/admin/settings">Settings</a>14 </nav>15 </aside>16 <main className="flex-1 p-8">{children}</main>17 </div>18);19}Now every page under '/admin/*' automatically gets this sidebar. Navigate between admin pages and the sidebar stays. No re-mount, no flash.
Route Groups: Organization Without URLs
Sometimes you want to organize routes without affecting the URL. Wrap folder names in parentheses:
1src/app/2├── (marketing)/3│ ├── layout.tsx ← Marketing-specific layout4│ ├── about/page.tsx → /about5│ └── pricing/page.tsx → /pricing6├── (dashboard)/7│ ├── layout.tsx ← Dashboard-specific layout8│ ├── settings/page.tsx → /settings9│ └── profile/page.tsx → /profile10└── layout.tsx ← Root layoutWhen I use route groups
• Marketing pages get a landing-page layout
• Dashboard pages get an app layout
• Same URL structure, different wrapping UI
Metadata & SEO
Next.js handles your
tags. Export a 'metadata' object from any page or layout:1// src/app/blog/page.tsx2import type { Metadata } from "next";34export const metadata: Metadata = {5title: "Blog | My Site",6description: "Read my latest articles about web development.",7openGraph: {8 title: "Blog | My Site",9 description: "Read my latest articles",10 images: ["/og-blog.png"],11},12};1314export default function BlogPage() {15return <h1>Blog</h1>;16}Child metadata merges with and overrides parent metadata. So your blog page gets the site-wide defaults PLUS its own title and description. No more manually managing
components.