Project Structure
The App Router organizes your application inside the app/ directory. Files and folders map directly to URL routes.
Top-Level Directories
my-next-app/
├── app/ # Routes, layouts, and pages
├── public/ # Static files served at /
├── components/ # Shared UI (convention, not required)
├── lib/ # Utilities and helpers
├── next.config.ts # Framework configuration
└── package.json
Only app/ and public/ are special to Next.js. Other folders are conventions your team defines.
Special Files in app/
| File | Purpose |
|---|---|
layout.tsx |
Shared UI wrapper for a route segment |
page.tsx |
Unique UI for a route (makes URL publicly accessible) |
loading.tsx |
Loading UI while content streams |
error.tsx |
Error boundary for a route segment |
not-found.tsx |
Custom 404 for a segment |
route.ts |
API endpoint (Route Handler) |
A folder becomes a route only when it contains a page.tsx or route.ts.
Root Layout
Every App Router project needs a root layout at app/layout.tsx:
import type { Metadata } from 'next';
import './globals.css';
export const metadata: Metadata = {
title: 'My Next.js App',
description: 'Built with Next.js App Router',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className="antialiased">
<header><nav>My App</nav></header>
{children}
<footer>© 2026</footer>
</body>
</html>
);
}
The root layout must include <html> and <body> tags. It wraps every page in your app.
Pages
app/page.tsx renders at /. Nested folders create nested URLs:
app/
├── page.tsx → /
├── about/page.tsx → /about
└── blog/[slug]/page.tsx → /blog/my-post
// app/about/page.tsx
export default function AboutPage() {
return (
<main>
<h1>About Us</h1>
</main>
);
}
Nested Layouts
Layouts nest automatically. A dashboard layout wraps all dashboard pages:
app/
├── layout.tsx # Root layout
├── page.tsx # /
└── dashboard/
├── layout.tsx # Dashboard layout (sidebar)
├── page.tsx # /dashboard
└── settings/page.tsx # /dashboard/settings
// app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex">
<aside>Sidebar</aside>
<main>{children}</main>
</div>
);
}
Navigating between /dashboard and /dashboard/settings keeps the sidebar mounted — only {children} re-renders.
Colocation and public/
Colocate components and styles next to routes — only special filenames (page, layout, etc.) become routes:
app/blog/
├── page.tsx
├── BlogList.tsx # Private — not a route
└── blog.module.css
Files in public/ are served at the root URL (public/logo.png → /logo.png).
Next: learn how folders and files become URL routes.