Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Important
Security Advisory: React2Shell & two new vulnerabilities
Find out more

layout.js

Last updated October 20, 2025

Thelayout file is used to define a layout in your Next.js application.

app/dashboard/layout.tsx
exportdefaultfunctionDashboardLayout({  children,}: {  children:React.ReactNode}) {return <section>{children}</section>}

Aroot layout is the top-most layout in the rootapp directory. It is used to define the<html> and<body> tags and other globally shared UI.

app/layout.tsx
exportdefaultfunctionRootLayout({  children,}: {  children:React.ReactNode}) {return (    <htmllang="en">      <body>{children}</body>    </html>  )}

Reference

Props

children (required)

Layout components should accept and use achildren prop. During rendering,children will be populated with the route segments the layout is wrapping. These will primarily be the component of a childLayout (if it exists) orPage, but could also be other special files likeLoading orError when applicable.

params (optional)

A promise that resolves to an object containing thedynamic route parameters object from the root segment down to that layout.

app/dashboard/[team]/layout.tsx
exportdefaultasyncfunctionLayout({  children,  params,}: {  children:React.ReactNode  params:Promise<{ team:string }>}) {const {team }=await params}
Example RouteURLparams
app/dashboard/[team]/layout.js/dashboard/1Promise<{ team: '1' }>
app/shop/[tag]/[item]/layout.js/shop/1/2Promise<{ tag: '1', item: '2' }>
app/blog/[...slug]/layout.js/blog/1/2Promise<{ slug: ['1', '2'] }>
  • Since theparams prop is a promise. You must useasync/await or React'suse function to access the values.
    • In version 14 and earlier,params was a synchronous prop. To help with backwards compatibility, you can still access it synchronously in Next.js 15, but this behavior will be deprecated in the future.

Layout Props Helper

You can type layouts withLayoutProps to get a strongly typedparams and named slots inferred from your directory structure.LayoutProps is a globally available helper.

app/dashboard/layout.tsx
exportdefaultfunctionLayout(props:LayoutProps<'/dashboard'>) {return (    <section>      {props.children}      {/* If you have app/dashboard/@analytics, it appears as a typed slot: */}      {/* {props.analytics} */}    </section>  )}

Good to know:

  • Types are generated duringnext dev,next build ornext typegen.
  • After type generation, theLayoutProps helper is globally available. It doesn't need to be imported.

Root Layout

Theapp directorymust include aroot layout, which is the top-most layout in the rootapp directory. Typically, the root layout isapp/layout.js.

app/layout.tsx
exportdefaultfunctionRootLayout({  children,}: {  children:React.ReactNode}) {return (    <html>      <body>{children}</body>    </html>  )}
  • The root layoutmust define<html> and<body> tags.
    • You shouldnot manually add<head> tags such as<title> and<meta> to root layouts. Instead, you should use theMetadata API which automatically handles advanced requirements such as streaming and de-duplicating<head> elements.
  • You can useroute groups to createmultiple root layouts.
    • Navigatingacross multiple root layouts will cause afull page load (as opposed to a client-side navigation). For example, navigating from/cart that usesapp/(shop)/layout.js to/blog that usesapp/(marketing)/layout.js will cause a full page load. Thisonly applies to multiple root layouts.
  • The root layout can be under adynamic segment, for example when implementinginternationalization withapp/[lang]/layout.js.

Caveats

Request Object

Layouts are cached in the client during navigation to avoid unnecessary server requests.

Layouts do not rerender. They can be cached and reused to avoid unnecessary computation when navigating between pages. By restricting layouts from accessing the raw request, Next.js can prevent the execution of potentially slow or expensive user code within the layout, which could negatively impact performance.

To access the request object, you can useheaders andcookies APIs inServer Components and Functions.

app/shop/layout.tsx
import { cookies }from'next/headers'exportdefaultasyncfunctionLayout({ children }) {constcookieStore=awaitcookies()consttheme=cookieStore.get('theme')return'...'}

Query params

Layouts do not rerender on navigation, so they cannot access search params which would otherwise become stale.

To access updated query parameters, you can use the PagesearchParams prop, or read them inside a Client Component using theuseSearchParams hook. Since Client Components re-render on navigation, they have access to the latest query parameters.

app/ui/search.tsx
'use client'import { useSearchParams }from'next/navigation'exportdefaultfunctionSearch() {constsearchParams=useSearchParams()constsearch=searchParams.get('search')return'...'}
app/shop/layout.tsx
import Searchfrom'@/app/ui/search'exportdefaultfunctionLayout({ children }) {return (    <>      <Search />      {children}    </>  )}

Pathname

Layouts do not re-render on navigation, so they do not access pathname which would otherwise become stale.

To access the current pathname, you can read it inside a Client Component using theusePathname hook. Since Client Components re-render during navigation, they have access to the latest pathname.

app/ui/breadcrumbs.tsx
'use client'import { usePathname }from'next/navigation'// Simplified breadcrumbs logicexportdefaultfunctionBreadcrumbs() {constpathname=usePathname()constsegments=pathname.split('/')return (    <nav>      {segments.map((segment, index)=> (        <spankey={index}>          {' > '}          {segment}        </span>      ))}    </nav>  )}
app/docs/layout.tsx
import { Breadcrumbs }from'@/app/ui/Breadcrumbs'exportdefaultfunctionLayout({ children }) {return (    <>      <Breadcrumbs />      <main>{children}</main>    </>  )}

Fetching Data

Layouts cannot pass data to theirchildren. However, you can fetch the same data in a route more than once, and use Reactcache to dedupe the requests without affecting performance.

Alternatively, when usingfetchin Next.js, requests are automatically deduped.

app/lib/data.ts
exportasyncfunctiongetUser(id:string) {constres=awaitfetch(`https://.../users/${id}`)returnres.json()}
app/dashboard/layout.tsx
import { getUser }from'@/app/lib/data'import { UserName }from'@/app/ui/user-name'exportdefaultasyncfunctionLayout({ children }) {constuser=awaitgetUser('1')return (    <>      <nav>        {/* ... */}        <UserNameuser={user.name} />      </nav>      {children}    </>  )}
app/dashboard/page.tsx
import { getUser }from'@/app/lib/data'import { UserName }from'@/app/ui/user-name'exportdefaultasyncfunctionPage() {constuser=awaitgetUser('1')return (    <div>      <h1>Welcome {user.name}</h1>    </div>  )}

Accessing child segments

Layouts do not have access to the route segments below itself. To access all route segments, you can useuseSelectedLayoutSegment oruseSelectedLayoutSegments in a Client Component.

app/ui/nav-link.tsx
'use client'import Linkfrom'next/link'import { useSelectedLayoutSegment }from'next/navigation'exportdefaultfunctionNavLink({  slug,  children,}: {  slug:string  children:React.ReactNode}) {constsegment=useSelectedLayoutSegment()constisActive= slug=== segmentreturn (    <Linkhref={`/blog/${slug}`}// Change style depending on whether the link is activestyle={{ fontWeight: isActive?'bold':'normal' }}    >      {children}    </Link>  )}
app/blog/layout.tsx
import { NavLink }from'./nav-link'import getPostsfrom'./get-posts'exportdefaultasyncfunctionLayout({  children,}: {  children:React.ReactNode}) {constfeaturedPosts=awaitgetPosts()return (    <div>      {featuredPosts.map((post)=> (        <divkey={post.id}>          <NavLinkslug={post.slug}>{post.title}</NavLink>        </div>      ))}      <div>{children}</div>    </div>  )}

Examples

Metadata

You can modify the<head> HTML elements such astitle andmeta using themetadata object orgenerateMetadata function.

app/layout.tsx
importtype { Metadata }from'next'exportconstmetadata:Metadata= {  title:'Next.js',}exportdefaultfunctionLayout({ children }: { children:React.ReactNode }) {return'...'}

Good to know: You shouldnot manually add<head> tags such as<title> and<meta> to root layouts. Instead, use theMetadata APIs which automatically handles advanced requirements such as streaming and de-duplicating<head> elements.

Active Nav Links

You can use theusePathname hook to determine if a nav link is active.

SinceusePathname is a client hook, you need to extract the nav links into a Client Component, which can be imported into your layout:

app/ui/nav-links.tsx
'use client'import { usePathname }from'next/navigation'import Linkfrom'next/link'exportfunctionNavLinks() {constpathname=usePathname()return (    <nav>      <LinkclassName={`link${pathname==='/'?'active':''}`}href="/">        Home      </Link>      <LinkclassName={`link${pathname==='/about'?'active':''}`}href="/about"      >        About      </Link>    </nav>  )}
app/layout.tsx
import { NavLinks }from'@/app/ui/nav-links'exportdefaultfunctionLayout({ children }: { children:React.ReactNode }) {return (    <htmllang="en">      <body>        <NavLinks />        <main>{children}</main>      </body>    </html>  )}

Displaying content based onparams

Usingdynamic route segments, you can display or fetch specific content based on theparams prop.

app/dashboard/layout.tsx
exportdefaultasyncfunctionDashboardLayout({  children,  params,}: {  children:React.ReactNode  params:Promise<{ team:string }>}) {const {team }=await paramsreturn (    <section>      <header>        <h1>Welcome to {team}'s Dashboard</h1>      </header>      <main>{children}</main>    </section>  )}

Readingparams in Client Components

To useparams in a Client Component (which cannot beasync), you can use React'suse function to read the promise:

app/page.tsx
'use client'import { use }from'react'exportdefaultfunctionPage({  params,}: {  params:Promise<{ slug:string }>}) {const {slug }=use(params)}

Version History

VersionChanges
v15.0.0-RCparams is now a promise. Acodemod is available.
v13.0.0layout introduced.

Was this helpful?

supported.

[8]ページ先頭

©2009-2025 Movatter.jp