I am in a basic, early-stage NextJS project and want to use the RootLayout, but changes to this file (including deleting it) have no effect on how my pages are rendered.
I generated my NextJS 13 project as described in the NextJS docs, like this:
npx create-next-app@latest
This resulted in a file structure like this:
src
- app
- favicon.ico
- globals.css
- layout.tsx
- page.tsx
- pages
- example-page.tsx
In src/app/layout.tsx
, the RootLayout
component is defined, including html
and body
tags, and the {children}
are passed here to the body. It looks like this by default:
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
{children}
</body>
</html>
)
}
In several places, the NextJS documentation states clearly that the RootLayout
component defined in app/layout.tsx
will be the basis for all routing/pages in your app. Here is one example: https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts
The top-most layout is called the Root Layout. This required layout is shared across all pages in an application. Root layouts must contain html and body tags.
Doesn't get much more clear than that!
In practice I'm not seeing this RootLayout being used at all. I first encountered this issue when trying to apply app-level Context, like so:
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
<MyContextProvider>
{children}
</MyContextProvider>
</body>
</html>
)
}
I was encountering trouble with this approach, and in my investigation of why, discovered that even something as simple as a div
was not being included in my example-page.tsx
render. In the following code, I expected to find a div
with the text content "Test div" rendered somewhere in the browser:
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
{/* This div does not render in the browser whatsoever */}
<div>Test div</div>
{children}
</body>
</html>
)
}
But this was not the case. Just to see what would happen, I deleted layout.tsx
completely, expecting to see the build or app fail is some way, and instead my app still works.
And incidentally, if the RootLayout isn't being used, and I haven't created any other custom layouts of my own, where is NextJS getting its base html
and body
template from to build/render these pages?
In NextJS 13.x, files defining pages go in app
folder subdirectories and should be named page.tsx
(or page.jsx
as appropriate), e.g. src/app/login/page.tsx
. In my folder structure from the original question you can see I was still using the NextJS 12.x file structure with a pages
directory. The layout.tsx
file will not pick up pages placed there. In NextJS 13.x, the old 12.x way of doing things is permitted in parallel with the new way. This is, in fact, alluded to in the documentation.