App Router file-system routing and app directory
Next.js uses file-system routing where routes are determined by file structure. Create an `app` folder, and inside it create a `layout.tsx` file (the required root layout containing `<html>` and `<body>` tags) and a `page.tsx` file (the home page). Both will be rendered when the user visits the root of the application (`/`).
Auto-creation of root layout
If you forget to create the root layout, Next.js will automatically create this file when running the development server with `next dev`.
Root layout example for App Router
Example root layout file at `app/layout.tsx`:
```tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
```
Optional src folder in App Router
You can optionally use a `src` folder in the root of your project to separate your application's code from configuration files.
Home page example for App Router
Example home page file at `app/page.tsx`:
```tsx
export default function Page() {
return <h1>Hello, Next.js!</h1>
}
```
Open Graph and Twitter metadata files
Social media metadata files: `opengraph-image` (.jpg .jpeg .png .gif) for Open Graph image file or (.js .ts .tsx) for generated Open Graph image; `twitter-image` (.jpg .jpeg .png .gif) for Twitter image file or (.js .ts .tsx) for generated Twitter image.
App router top-level folders
The top-level folders in a Next.js App Router project are: `app` for the App Router, `pages` for the Pages Router, `public` for static assets to be served, and `src` as an optional application source folder.
Top-level configuration and utility files
Top-level files used to configure a Next.js application include: `next.config.js` (Next.js configuration), `package.json` (project dependencies and scripts), `instrumentation.ts` (OpenTelemetry and Instrumentation), `proxy.ts` (Next.js request proxy), `.env`, `.env.local`, `.env.production`, `.env.development` (environment variables), `eslint.config.mjs` (ESLint configuration), `.gitignore` (Git ignore rules), `next-env.d.ts` (TypeScript declarations), `tsconfig.json` (TypeScript configuration), and `jsconfig.json` (JavaScript configuration).
Route groups organizational purposes
Route groups, created by wrapping a folder in parentheses `(folderName)`, are for organizational purposes and are not included in the route's URL path. Route groups are useful for organizing routes by site section, intent, or team (e.g., marketing pages, admin pages); enabling nested layouts in the same route segment level; creating multiple nested layouts in the same segment; creating multiple root layouts; and adding a layout to a subset of routes in a common segment.
Route groups and private folders
Route groups use parentheses syntax `(group)` to organize code without changing URLs; e.g., `app/(marketing)/page.tsx` maps to `/` with the group omitted from the path. Private folders use underscore prefix `_folder` to colocate non-routable files safely; e.g., `app/blog/_components/Post.tsx` and `app/blog/_lib/data.ts` are not routable. Private folders are useful for separating UI logic from routing logic and organizing internal files consistently.
Nested routes in App Router
Nested routes example paths and their corresponding URL patterns: `app/layout.tsx` (root layout, wraps all routes, no URL); `app/blog/layout.tsx` (wraps `/blog` and descendants, no URL); `app/page.tsx` (public route at `/`); `app/blog/page.tsx` (public route at `/blog`); `app/blog/authors/page.tsx` (public route at `/blog/authors`). Folders define URL segments, nesting folders nests segments, and layouts at any level wrap their child segments.
App Router routing file conventions
Routing files in the App Router with their accepted file extensions and purposes: `layout` (.js .jsx .tsx) for layouts; `page` (.js .jsx .tsx) for pages; `loading` (.js .jsx .tsx) for loading UI; `not-found` (.js .jsx .tsx) for not found UI; `error` (.js .jsx .tsx) for error UI; `global-error` (.js .jsx .tsx) for global error UI; `route` (.js .ts) for API endpoints; `template` (.js .jsx .tsx) for re-rendered layouts; `default` (.js .jsx .tsx) for parallel route fallback pages.
Metadata file conventions for app icons
App icon metadata files: `favicon` (.ico) for favicon; `icon` (.ico .jpg .jpeg .png .svg) for app icon file or (.js .ts .tsx) for generated app icon; `apple-icon` (.jpg .jpeg .png) for Apple app icon file or (.js .ts .tsx) for generated Apple app icon.
Route accessibility in App Router
A route in the App Router is not publicly accessible until a `page.js` or `route.js` file is added to a route segment. Only the content returned by `page.js` or `route.js` is sent to the client. This means project files can be safely colocated inside route segments without accidentally being routable.
Component rendering hierarchy in App Router
In the App Router, special file components are rendered in a specific hierarchy: `layout.js`, `template.js`, `error.js` (React error boundary), `loading.js` (React suspense boundary), `not-found.js` (React error boundary for not found UI), then `page.js` or nested `layout.js`. These components render recursively in nested routes, meaning route segment components nest inside their parent segment components.
SEO metadata file conventions
SEO metadata files: `sitemap` (.xml) for sitemap file or (.js .ts) for generated sitemap; `robots` (.txt) for robots file or (.js .ts) for generated robots file.
Creating URL segments starting with underscore
To create a URL segment that starts with an underscore, prefix the folder name with `%5F` (the URL-encoded form of an underscore), such as `%5FfolderName`. This allows you to have a URL segment beginning with an underscore while still using the private folder naming convention for other purposes.
Using src folder in Next.js
Next.js supports storing application code, including the `app` directory, inside an optional `src` folder. This separates application code from project configuration files which mostly live in the root of the project.
Dynamic routes in App Router
Dynamic routes in the App Router use square brackets for parameterization. `[segment]` matches a single dynamic segment (e.g., `app/blog/[slug]/page.tsx` matches `/blog/my-first-post`). `[...segment]` is a catch-all that matches multiple segments (e.g., `app/shop/[...slug]/page.tsx` matches `/shop/clothing` and `/shop/clothing/shirts`). `[[...segment]]` is an optional catch-all that matches zero or more segments (e.g., `app/docs/[[...slug]]/page.tsx` matches `/docs`, `/docs/layouts-and-pages`, and `/docs/api-reference/use-router`). Access parameter values via the `params` prop.
Parallel and intercepted routes patterns
Parallel routes use `@folder` syntax for named slots rendered by a parent layout (e.g., sidebar + main content). Intercepted routes use patterns to render another route without changing the URL: `(.)folder` intercepts at the same level, `(..)folder` intercepts the parent level, `(..)(..)folder` intercepts two levels up, and `(...)folder` intercepts from the root.
Multiple root layouts with route groups
To create multiple root layouts, remove the top-level `layout.js` file and add a `layout.js` file inside each route group. Each root layout must include `<html>` and `<body>` tags. This pattern is useful for partitioning an application into sections that have completely different UIs or experiences.
Private folder convention for opting out of routing
Private folders are created by prefixing a folder with an underscore: `_folderName`. This indicates the folder is a private implementation detail and opts the folder and all its subfolders out of the routing system. Private folders are useful for separating UI logic from routing logic, consistently organizing internal files, sorting and grouping files in code editors, and avoiding potential naming conflicts with future Next.js file conventions.
Example: Page component with dynamic segment
export default async function BlogPostPage({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const post = await getPost(slug)
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
)
}
This example shows a page component accessing a dynamic segment parameter.
LayoutProps helper for layout components
LayoutProps is a global utility type helper that infers children and named slots from your route structure. Use it to type props for layout components, for example: export default function Layout(props: LayoutProps<'/dashboard'>) { return <section>{props.children}</section> }. Named slots appear as typed properties (e.g. props.analytics for @analytics folders). No imports required.
searchParams opts page into dynamic rendering
Using the searchParams prop in a page opts that page into dynamic rendering because it requires an incoming request to read the search parameters from.
Link is primary navigation method
Link is the primary way to navigate between routes in Next.js. You can also use the useRouter hook for more advanced navigation.
When to use searchParams vs useSearchParams
Use the searchParams prop when you need search parameters to load data for the page (e.g. pagination, filtering from a database). Use useSearchParams hook when search parameters are used only on the client (e.g. filtering a list already loaded via props). Use new URLSearchParams(window.location.search) in callbacks or event handlers to read search params without triggering re-renders.
Static routes resolve params to empty object
For static routes (routes without dynamic segments), the params property resolves to an empty object {}.
Link component for navigation
The Link component is a built-in Next.js component that extends the HTML a tag to provide prefetching and client-side navigation. Import Link from 'next/link' and use the href prop to navigate between routes.
searchParams prop in Server Component pages
In a Server Component page, you can access search parameters using the searchParams prop, which is typed as Promise<{ [key: string]: string | string[] | undefined }>. You must await searchParams to access the values.
Dynamic segment params prop structure
In page components with dynamic segments, the params prop is typed as Promise<{ [segmentName]: string }>. You must await params to access the dynamic segment values. For example, in app/blog/[slug]/page.tsx, params is Promise<{ slug: string }>.
Nested layouts wrap child layouts
Layouts in the folder hierarchy are automatically nested, meaning they wrap child layouts via their children prop. Add layout files inside specific route segment folders to create nested layouts.
Example: Link component usage
import Link from 'next/link'
import { getPosts } from '@/lib/posts'
export default async function Posts() {
const posts = await getPosts()
return (
<ul>
{posts.map((post) => (
<li key={post.slug}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
This example shows how to use the Link component to navigate between routes.
Nested routes using folder hierarchy
Folders are used to define route segments that map to URL segments. Files like page and layout create UI for a segment. Nest folders inside each other to create nested routes.
Creating a layout component
A layout is UI shared between multiple pages. Define a layout by default exporting a React component from a layout file. The component must accept a children prop which can be a page or another layout.
Route Props Helpers are globally available
PageProps and LayoutProps are global helpers that are generated when running next dev, next build, or next typegen. No imports are required to use them.
Layouts within Dynamic Segments can access params
Nested layouts within Dynamic Segments can also access the params props.
File-system based routing in Next.js
Next.js uses file-system based routing, meaning you define routes using folders and files in the app directory to structure your application.
PageProps helper for page components
PageProps is a global utility type helper that infers params and searchParams from your route structure. Use it to type props for page components, for example: export default async function Page(props: PageProps<'/blog/[slug]'>) { const { slug } = await props.params }. No imports required.
Dynamic route segments with square brackets
Wrapping a folder name in square brackets (e.g. [slug]) creates a dynamic route segment which generates multiple pages from data, such as blog posts or product pages.
Creating a page with page file
A page is UI rendered on a specific route. Create a page by adding a page file (page.tsx or page.js) inside the app directory and default exporting a React component.
Root layout is required
The root layout is defined at the root of the app directory and is required. It must contain html and body tags.
Example: searchParams in Server Component page
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const filters = (await searchParams).filters
}
This example shows how to access and await search parameters in a Server Component page.
Layout properties: state preservation and no rerender on navigation
When navigating between pages, layouts preserve state, remain interactive, and do not rerender.
Benefits of loading.tsx
loading.tsx provides immediate navigation and visual feedback for the user. Shared layouts remain interactive and navigation is interruptible. It improves Core Web Vitals including TTFB (Time to First Byte), FCP (First Contentful Paint), and TTI (Time to Interactive).
loading.tsx enables partial prefetching of dynamic routes
Creating a loading.tsx file in a route folder enables partial prefetching of dynamic routes. Next.js automatically wraps the page.tsx contents in a <Suspense> boundary. The prefetched fallback UI is shown while the route loads, then swapped for actual content once ready.
loading.js blocks navigation if layout accesses uncached data
A layout that accesses uncached or runtime data (such as cookies(), headers(), or uncached fetches) does not fall back to a same route segment loading.js. Instead, it blocks navigation until the layout finishes rendering. Wrap the uncached access in its own <Suspense> boundary with a fallback, or move the data fetching into page.js where loading.js can cover it.
loading.js streams entire page
Create a loading.js file in the same folder as your page to stream the entire page while data is being fetched. For example, to stream app/blog/page.js, add loading.js inside the app/blog folder. Behind the scenes, loading.js is nested inside layout.js and automatically wraps the page.js file and any children in a <Suspense> boundary.
Static local image import example
Example of using statically imported local image:
import Image from 'next/image'
import ProfileImage from './profile.png'
export default function Page() {
return (
<Image
src={ProfileImage}
alt="Picture of the author"
// width and height automatically provided
// blurDataURL automatically provided
// placeholder="blur" // Optional
/>
)
}
Remote image URL pattern example configuration
Example next.config.js configuration restricting images to AWS S3: { images: { remotePatterns: [{ protocol: 'https', hostname: 's3.amazonaws.com', port: '', pathname: '/my-bucket/**', search: '' }] } }
Configure remotePatterns in next.config.js for remote images
To safely allow images from remote servers, define a list of supported URL patterns in next.config.js using the images.remotePatterns configuration. Each pattern object can include: protocol (string), hostname (string), port (string), pathname (string with wildcard support), and search (string). Be as specific as possible to prevent malicious usage.
Remote images fill property as alternative to dimensions
As an alternative to providing width and height for remote images, you can use the fill property to make the image fill the size of the parent element.
Dynamic image imports must include static prefix
When using dynamic imports for images, the path must include a static prefix (like ../content/blog/images/). Be as specific as possible since all files matching that prefix are bundled. Only files in the specified directory are included, so external input cannot reach outside of it.
Remote images require manual width and height
For remote images, since Next.js does not have access to remote files during build, you must manually provide the width, height, and optional blurDataURL props. The width and height are used to infer the correct aspect ratio and avoid layout shift.
Dynamic imports in Server Components for image metadata
If you cannot use a static import for images, you can use a dynamic import() in a Server Component to automatically get width, height, and blurDataURL metadata. Example: const { default: image } = await import(`../content/blog/images/${imageFilename}`)
Blur placeholder with statically imported images
When using statically imported images, you can optionally add placeholder="blur" to display a blur-up effect while the image is loading. The blurDataURL is automatically generated.
Statically imported images auto-determine dimensions
When an image is statically imported as a module (e.g., import ProfileImage from './profile.png'), Next.js automatically determines the intrinsic width and height values. These are used to determine image ratio and prevent Cumulative Layout Shift while the image loads. The blurDataURL is also automatically provided.
Remote image example
Example of using a remote image:
import Image from 'next/image'
export default function Page() {
return (
<Image
src="https://s3.amazonaws.com/my-bucket/profile.png"
alt="Picture of the author"
width={500}
height={500}
/>
)
}
Dynamic image import with path alias example
Example of dynamic image import using a path alias (e.g., @/):
const { default: image } = await import(
`@/content/blog/images/${imageFilename}`
)
Dynamic image import in Server Component example
Example of dynamic image import in a Server Component:
import Image from 'next/image'
async function PostImage({ imageFilename, alt }: { imageFilename: string; alt: string }) {
const { default: image } = await import(
`../content/blog/images/${imageFilename}`
)
// image contains width, height, and blurDataURL
return <Image src={image} alt={alt} />
}