loading.js file convention purpose
The loading.js special file creates meaningful Loading UI using React Suspense. It shows an instant loading state from the server while the content of a route segment streams in. Once streaming is complete, the new content is automatically swapped in.
loading.js with uncached or runtime data in layout
If the layout accesses uncached or runtime data (e.g. cookies(), headers(), or uncached fetches), loading.js will not show a fallback for it. Without Cache Components, navigation blocks until the layout finishes rendering. With Cache Components, uncached or runtime data access in the layout must be explicitly wrapped in <Suspense>, otherwise Next.js guides you with a build-time error. The static shell streams first, and the uncached content fills in. To ensure instant navigation, move uncached data fetching from layout.js into page.js, or wrap the runtime data access in your layout in its own <Suspense> boundary.
loading.js instant loading states
An instant loading state is fallback UI shown immediately upon navigation. You can prerender loading indicators such as skeletons and spinners, or a small but meaningful part of future screens such as a cover photo or title. Create a loading state by adding a loading.js file inside a folder.
loading.js prefetch and navigation behavior
The fallback UI is prefetched, making navigation immediate unless prefetching hasn't completed. Navigation is interruptible, meaning changing routes does not need to wait for the content of the route to fully load before navigating to another route. Shared layouts remain interactive while new route segments load.
loading.js Suspense boundary wrapping behavior
In the same folder, loading.js is nested inside layout.js and automatically wraps the page.js file and any children below in a <Suspense> boundary. In the component hierarchy, loading.js wraps not-found.js, page.js, and nested layout.js files in a <Suspense> boundary. It does not wrap the layout.js, template.js, or error.js in the same segment.
loading.js SEO behavior for bots
For bots that only scrape static HTML and cannot execute JavaScript like a full browser (such as Twitterbot), Next.js resolves generateMetadata before streaming UI, and metadata is placed in the <head> of the initial HTML. Otherwise, streaming metadata may be used. Next.js automatically detects user agents to choose between blocking and streaming behavior. Since streaming is server-rendered, it does not impact SEO.
loading.js browser streaming buffer limit
Some browsers buffer a streaming response. You may not see the streamed response until the response exceeds 1024 bytes. This typically only affects 'hello world' applications, but not real applications.
Data fetching in layout and page
Example showing fetching the same data in both layout and page, where Next.js automatically dedupes fetch requests. import { getUser } from '@/app/lib/data'; Layout uses: const user = await getUser('1'); Page uses: const user = await getUser('1');
layout.js file convention
The layout file is used to define a layout in a Next.js application. It is a file convention that exports a default function component accepting a children prop.
layout.js component hierarchy position
In the component hierarchy, layout.js is the outermost component in a route segment. It wraps template.js, error.js, loading.js, not-found.js, and page.js.
Root layout definition and requirement
A root layout is the top-most layout in the root app directory. The app directory must include a root layout, which is typically app/layout.js. The root layout must define <html> and <body> tags.
layout.js children prop
The children prop is required in layout components. During rendering, children will be populated with the route segments the layout is wrapping, typically the component of a child Layout or Page, but could also be other special files like Loading or Error when applicable.
LayoutProps helper for type safety
You can type layouts with LayoutProps to get a strongly typed params and named slots inferred from your directory structure. LayoutProps is a globally available helper that does not need to be imported. Types are generated during next dev, next build, or next typegen.
Multiple root layouts in Next.js
You can create multiple root layouts. Any layout without a layout.js above it is a root layout. Two common approaches: using route groups like app/(shop)/layout.js and app/(marketing)/layout.js, or omitting app/layout.js so layouts in subdirectories like app/dashboard/layout.js and app/blog/layout.js each become root layouts for their respective directories. Navigating across multiple root layouts will cause a full page load (as opposed to a client-side navigation).
Root layout under dynamic segment
The root layout can be under a dynamic segment, for example when implementing internationalization with app/[lang]/layout.js. Dynamic segments before the root layout are root parameters and can be read from any Server Component with next/root-params.
Layouts are cached during client navigation
Layouts are cached in the client during navigation to avoid unnecessary server requests. Layouts do not rerender and can be cached and reused to avoid unnecessary computation when navigating between pages.
Accessing request object in layouts
Layouts do not have direct access to the raw request object. To access the request object, you can use the headers and cookies APIs in Server Components and Functions. Direct access is restricted to prevent execution of potentially slow or expensive user code within the layout, which could negatively impact performance.
Query params not accessible in layouts
Layouts do not rerender on navigation, so they cannot access search params which would otherwise become stale. To access updated query parameters, use the Page searchParams prop or read them inside a Client Component using the useSearchParams hook, since Client Components re-render on navigation and have access to the latest query parameters.
Pathname not accessible in layouts
Layouts do not re-render on navigation, so they do not access pathname which would otherwise become stale. To access the current pathname, read it inside a Client Component using the usePathname hook. Since Client Components re-render during navigation, they have access to the latest pathname.
loading.js behavior with layouts
Because loading.js sits below layout.js in the component hierarchy, it cannot show a fallback for uncached or runtime data access in the layout itself, such as calling cookies(), headers(), or making uncached fetches. Without Cache Components: the navigation will block until the layout finishes rendering, and the loading.js fallback will not be shown. With Cache Components: loading.js is treated as a regular Suspense boundary rather than a special prefetch marker, and uncached or runtime data access in the layout must be explicitly wrapped in its own Suspense boundary, otherwise Next.js guides with a build-time error.
Data fetching in layouts
Layouts cannot pass data to their children. However, you can fetch the same data in a route more than once and use React cache to dedupe the requests without affecting performance. Alternatively, when using fetch in Next.js, requests are automatically deduped.
Accessing child segments from layouts
Layouts do not have access to the route segments below itself. To access all route segments, you can use useSelectedLayoutSegment or useSelectedLayoutSegments in a Client Component.
Metadata in layouts
You can modify the <head> HTML elements such as title and meta using the metadata object or generateMetadata function. You should not manually add <head> tags such as <title> and <meta> to root layouts. Instead, use the Metadata APIs which automatically handles advanced requirements such as streaming and de-duplicating <head> elements.
layout.js params prop example for dynamic routes
Example Route: app/dashboard/[team]/layout.js, URL: /dashboard/1, params: Promise<{ team: '1' }>. Example Route: app/shop/[tag]/[item]/layout.js, URL: /shop/1/2, params: Promise<{ tag: '1', item: '2' }>. Example Route: app/blog/[...slug]/layout.js, URL: /blog/1/2, params: Promise<{ slug: ['1', '2'] }>.
layout.js basic example with children
A basic layout component receives a children prop and returns JSX wrapping the children. Example: export default function DashboardLayout({ children }: { children: React.ReactNode }) { return <section>{children}</section> }
Root layout basic structure
A root layout must define html and body tags and wrap the children prop inside. Example: export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body>{children}</body> </html> ) }
layout.js with dynamic params example
Example showing how to access dynamic route parameters in a layout using async/await: export default async function Layout({ children, params }: { children: React.ReactNode, params: Promise<{ team: string }> }) { const { team } = await params }
LayoutProps helper usage example
Example using LayoutProps for type-safe layout props: export default function Layout(props: LayoutProps<'/dashboard'>) { return ( <section> {props.children} {/* If you have app/dashboard/@analytics, it appears as a typed slot: */} {/* {props.analytics} */} </section> ) }
Using cookies in layout
Example of accessing cookies in a layout using the cookies API: import { cookies } from 'next/headers'; export default async function Layout({ children }) { const cookieStore = await cookies(); const theme = cookieStore.get('theme'); return '...' }
Accessing search params in layouts with Client Component
Example of using useSearchParams hook in a Client Component to access query params, then importing that Client Component into a layout: 'use client'; import { useSearchParams } from 'next/navigation'; export default function Search() { const searchParams = useSearchParams(); const search = searchParams.get('search'); return '...' }
Accessing pathname in layouts with Client Component
Example of using usePathname hook in a Client Component to access the current pathname, then importing that Client Component into a layout: 'use client'; import { usePathname } from 'next/navigation'; export default function Breadcrumbs() { const pathname = usePathname(); const segments = pathname.split('/'); return ( <nav> {segments.map((segment, index) => ( <span key={index}> {' > '} {segment} </span> ))} </nav> ) }
Wrapping uncached data in Suspense within layout
Example showing how to wrap runtime data access in a layout in its own Suspense boundary with a fallback: import { Suspense } from 'react'; import { NavSkeleton } from './nav-skeleton'; import { DashboardNav } from './dashboard-nav'; export default function Layout({ children }: { children: React.ReactNode }) { return ( <> <Suspense fallback={<NavSkeleton />}> <DashboardNav /> </Suspense> <main>{children}</main> </> ) }
Using useSelectedLayoutSegment in layout
Example of using useSelectedLayoutSegment hook in a Client Component to determine active nav links, then importing that Client Component into a layout: 'use client'; import { useSelectedLayoutSegment } from 'next/navigation'; export default function NavLink({ slug, children }: { slug: string; children: React.ReactNode }) { const segment = useSelectedLayoutSegment(); const isActive = slug === segment; return ( <Link href={`/blog/${slug}`} style={{ fontWeight: isActive ? 'bold' : 'normal' }}> {children} </Link> ) }
Metadata object in layout
Example of using the metadata object in a layout to set the page title: import type { Metadata } from 'next'; export const metadata: Metadata = { title: 'Next.js', }; export default function Layout({ children }: { children: React.ReactNode }) { return '...' }
Active nav links with usePathname
Example showing how to create active nav links using usePathname hook in a Client Component, then importing into layout: 'use client'; import { usePathname } from 'next/navigation'; import Link from 'next/link'; export function NavLinks() { const pathname = usePathname(); return ( <nav> <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/"> Home </Link> <Link className={`link ${pathname === '/about' ? 'active' : ''}`} href="/about"> About </Link> </nav> ) }
Displaying content based on params in layout
Example showing how to display content based on dynamic route params in a layout: export default async function DashboardLayout({ children, params }: { children: React.ReactNode, params: Promise<{ team: string }> }) { const { team } = await params; return ( <section> <header> <h1>Welcome to {team}'s Dashboard</h1> </header> <main>{children}</main> </section> ) }
Reading params in Client Component with use hook
Example showing how to use params in a Client Component by using React's use function to read the promise: 'use client'; import { use } from 'react'; export default function Page({ params }: { params: Promise<{ slug: string }> }) { const { slug } = use(params) }
layout.js version history
Version v15.0.0-RC: params is now a promise. A codemod is available. Version v13.0.0: layout introduced.
searchParams is plain JavaScript object not URLSearchParams
searchParams is a plain JavaScript object, not a URLSearchParams instance.
page example with params in dynamic route
Server Component example accessing params in a dynamic route:
```tsx
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
return <h1>Blog Post: {slug}</h1>
}
```
This example displays content based on the dynamic route parameter.
page example filtering with searchParams
Example handling filtering, pagination, or sorting with searchParams:
```tsx
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const { page = '1', sort = 'asc', query = '' } = await searchParams
return (
<div>
<h1>Product Listing</h1>
<p>Search query: {query}</p>
<p>Current page: {page}</p>
<p>Sort order: {sort}</p>
</div>
)
}
```
page example reading searchParams and params in Client Component
To use searchParams and params in a Client Component (which cannot be async), use React's use() function to read the promise:
```tsx
'use client'
import { use } from 'react'
export default function Page({
params,
searchParams,
}: {
params: Promise<{ slug: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const { slug } = use(params)
const { query } = use(searchParams)
}
```
page default export requirement
You can create a page by default exporting a component from the file.
params and searchParams changed to promises in v15
In Next.js v15.0.0-RC, params and searchParams became promises. A codemod is available to help with migration from earlier versions where they were synchronous.
Client Component pages can access searchParams with use hook
Client Component pages can access searchParams using React's use() hook. The searchParams prop has type Promise<{ [key: string]: string | string[] | undefined }>.
page params prop type and usage
The params prop is optional and is a promise that resolves to an object containing the dynamic route parameters from the root segment down to that page. Since params is a promise, you must use async/await or React's use() function to access the values. In Next.js 15 and later, params is a promise; in version 14 and earlier, params was synchronous but can still be accessed synchronously in Next.js 15 for backwards compatibility, though this behavior will be deprecated in the future.
page file component hierarchy
In the component hierarchy, page.js is the innermost file convention. It is wrapped by loading.js (Suspense boundary), error.js (error boundary), template.js, and layout.js in the same segment.
page file is the leaf of route subtree
A page is always the leaf of the route subtree. A page file is required to make a route segment publicly accessible.
page file conventions and file extensions
The page file allows you to define UI that is unique to a route. Page files can use the .js, .jsx, or .tsx file extensions. Pages are Server Components by default, but can be set to a Client Component.
page params examples by route
Dynamic route segments resolve params as follows: app/shop/[slug]/page.js with URL /shop/1 resolves to Promise<{ slug: '1' }>; app/shop/[category]/[item]/page.js with URL /shop/1/2 resolves to Promise<{ category: '1', item: '2' }>; app/shop/[...slug]/page.js with URL /shop/1/2 resolves to Promise<{ slug: ['1', '2'] }>.
page searchParams prop type and usage
The searchParams prop is optional and is a promise that resolves to an object containing the search parameters of the current URL, with type Promise<{ [key: string]: string | string[] | undefined }>. Since searchParams is a promise, you must use async/await or React's use() function to access the values. In version 14 and earlier, searchParams was synchronous but can still be accessed synchronously in Next.js 15, though this behavior will be deprecated in the future.
page searchParams examples by URL
Search parameters resolve searchParams as follows: /shop?a=1 resolves to Promise<{ a: '1' }>; /shop?a=1&b=2 resolves to Promise<{ a: '1', b: '2' }>; /shop?a=1&a=2 resolves to Promise<{ a: ['1', '2'] }>.
searchParams is request-time API causing dynamic rendering
searchParams is a request-time API whose values cannot be known ahead of time. Using searchParams will opt the page into dynamic rendering at request time.
searchParams with Cache Components determines prerendering
With Cache Components, where you access searchParams in the component tree determines how much of the page can be prerendered. See Maximizing the static shell.
PageProps helper for strongly typed page props
You can type pages with PageProps to get strongly typed params and searchParams from the route literal. PageProps is a globally available helper. Using a literal route (e.g. '/blog/[slug]') enables autocomplete and strict keys for params. Static routes resolve params to {}. Types are generated during next dev, next build, or with next typegen. After type generation, the PageProps helper is globally available and does not need to be imported.
public folder serves static files from root
Next.js can serve static files, like images, under a folder called `public` in the root directory. Files inside `public` can be referenced by code starting from the base URL (`/`). For example, the file `public/avatars/me.png` can be viewed by visiting the `/avatars/me.png` path.
public folder caching headers
Next.js cannot safely cache assets in the `public` folder because they may change. The default caching headers applied are: `Cache-Control: public, max-age=0`
Image component example with public folder
This example shows how to display an image from the public folder using the Image component from 'next/image':
```jsx
import Image from 'next/image'
export function Avatar({ id, alt }) {
return <Image src={`/avatars/${id}.png`} alt={alt} width="64" height="64" />
}
export function AvatarOfMe() {
return <Avatar id="me" alt="A portrait of me" />
}
```
metadata files should use special metadata files in app folder
For static metadata files, such as `robots.txt`, `favicon.ico`, etc, you should use special metadata files inside the `app` folder rather than placing them in the `public` folder.
Route Groups conflicting paths caveat
Routes in different route groups should not resolve to the same URL path. For example, (marketing)/about/page.js and (shop)/about/page.js would both resolve to /about and cause an error.