cf.completefrontend
Open lab My progress
THE NEXT.JS FIELD GUIDE

Templates and the file hierarchy

See how layout, template, error, loading, not-found and page nest in one folder, why template.tsx starts fresh for each page, and what default.tsx does.

By the end, you can
  • 01
    Name the nesting orderSay which special file wraps which, and what that means for loading states, errors and not-found screens.
  • 02
    Choose a template or a layoutTell what keeps its state between pages and what starts fresh, and pick template.tsx only when you want that.
  • 03
    Read the tree Next.js buildsSketch the components for an address from its folders, and know when a slot needs a default.tsx.

A wrapper that starts fresh for each page

In Layouts and pages you saw that a layout.tsx wraps every page in its folder, and stays on the screen, with its state, while the visitor moves between those pages. Most of the time that's what you want. Sometimes you want the opposite: a wrapper that starts fresh on each page. That's a template, a file named template.tsx.

Here are the tea shop's tea pages with both. The tea layout has the menu of teas and a cup counter. The template puts a box for tasting notes under each tea page. Like every example in this lesson, it's a real Next.js 16.4.3 project, built with next build and run with next start, and what it sent back was recorded.

The tea pages with a layout and a templateNext.js
app/teas/green/mint/
app/teas/template.tsx
import NotesBox from "./notes-box"; export default function TeasTemplate({ children }: { children: React.ReactNode }) {  return (    <div>      {children}      <NotesBox />    </div>  );}
Recorded from Next.js 16.4.3
localhost:3000/teas/greenTea shop
Home Teas

Cups brewed: 0 Brew a cup

Green tea

Light and fresh. $4 a box.

The page as the browser shows it when its HTML arrives, drawn with plain styles. Its JavaScript doesn't run here.

app/teas/template.tsx, the file shown first, looks like a layout. Line 3 takes children, the page, and types it as React.ReactNode, anything React can render. Line 6 puts the page there, and line 7 puts NotesBox under it. Click app/teas/notes-box.tsx: it starts with "use client", which marks where the part of the app that also runs in the browser begins, and line 6 keeps the notes in state. The template itself is a Server Component, as layouts and pages are by default; NotesBox is where the client part starts.

The Browser tab shows /teas/green: the shop's links, the tea menu and Cups brewed: 0 from the tea layout, the page, then Tasting notes from the template. Open the Network tab to see the nesting in the HTML: the tea layout's <section> holds its <nav>, the counter, and then the template's <div>; the <div> holds the page's <main> and the notes' <label>. Pick /teas/mint: the same layout and the same template, around a different page.

Three windows, one inside the other, for the page at /teas/green. The outermost is app/layout.tsx, with the links Home and Teas. Inside it is teas/layout.tsx, with the tea menu and the cup counter. Inside that is teas/template.tsx, with the tasting notes box, and in its middle the page, Green tea.app/layout.tsxHome Teasteas/layout.tsxGreen tea Mint tea · Cups brewed: 0teas/template.tsxpage.tsx: Green teaTasting notes
What wraps what on /teas/green, from the outside in, as the HTML in the Network tab nests it. The template sits between the tea layout and the page: it gets the page as children, and puts its notes box under it.
Real-life analogyA table and its placemats

A café sets each table once in the morning. Each new guest gets a fresh paper placemat, and doodles on it while they wait. When a guest leaves for a moment, the waiter puts their placemat aside, doodles and all, and gives it back if they return. The table never changes.

In real life: The café table, set the same way all day
In Next.js: The tea layout, the same for every tea page
In real life: A paper placemat on the table
In Next.js: The template, around the page
In real life: A fresh placemat for each new guest
In Next.js: A new copy of the template for each tea page
In real life: The last few placemats kept aside, in case those guests come back
In Next.js: Pages you left, kept hidden with their state: up to two beside the one on the screen
The main idea

A template is a layout that Next.js makes again for each page under it. template.tsx sits inside the layout of its folder and wraps the rest. A layout keeps one copy, and its state, for all its pages; a template gives each page its own copy, so state inside it starts fresh on a new page.

The order of special files in one folder

Six of the special files a folder can hold wrap each other in a fixed order, the same in every folder, which Loading UI listed briefly. Each row is one file, from the outside in: what it wraps, and what that means for you.

The special files of one folder, from the outside in
FileWhat it wrapsWhat that means for you
layout.tsxEverything else in its folder, and the folders below.It stays on the screen around every other screen of the folder, and keeps its state between the pages under it.
template.tsxThe error, loading and not-found screens and the page, inside the layout.It stays around those screens too. Next.js makes a new copy of it for each page under it.
error.tsxThe loading state, the not-found screen, the page and the folders below.It catches what breaks inside it, never in the layout.tsx or template.tsx beside it: errors there go to the folder above.
loading.tsxThe not-found screen, the page and the folders below, in a Suspense.Its fallback shows inside the layout and the template, as the recording of /teas/today shows.
not-found.tsxThe page and the folders below.When the page calls notFound(), this screen shows inside the layout and the template.
page.tsxNothing.The innermost part: what the address itself shows.
Six frames, each inside the one before: layout.tsx, then template.tsx, then error.tsx, then loading.tsx, then not-found.tsx, and page.tsx in the middle.layout.tsxtemplate.tsxerror.tsxloading.tsxnot-found.tsxpage.tsx
The special files of one folder, from the outside in. Each frame wraps everything inside it, never what is outside it. So error.tsx can catch an error in the page, but not one in the layout.tsx or template.tsx beside it.

You can see part of the order in a recording. Here the tea folder has all six files, plus a page for today's tea that reads its data for each request:

The tea folder with every special fileText
app/
  teas/
    green/
      page.tsx
    mint/
      page.tsx
    today/
      page.tsx
    error.tsx
    layout.tsx
    loading.tsx
    not-found.tsx
    page.tsx
    template.tsx
  layout.tsx
  page.tsx
Every special file in the tea folderNext.js
app/teas/green/mint/today/
app/teas/loading.tsx
export default function Loading() {  return <p>Loading the tea…</p>;}
Recorded from Next.js 16.4.3

GET /teas/today200

Response headers
Vary rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
x-nextjs-stale-time 300
x-nextjs-prerender 1
x-nextjs-postponed 1
X-Powered-By Next.js
Cache-Control private, no-cache, no-store, max-age=0, must-revalidate
Content-Type text/html; charset=utf-8

The HTML that arrived, one element per line, with the code of its 19 scripts left out

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="preload" as="script" fetchpriority="low" href="/_next/static/chunks/1x6obpmlu1_c2.js">
    <script src="/_next/static/chunks/06bs-nf19b2js.js" async=""></script>
    <script src="/_next/static/chunks/2ki52vdnbo2ft.js" async=""></script>
    <script src="/_next/static/chunks/3l_qmp-61z4yc.js" async=""></script>
    <script src="/_next/static/chunks/turbopack-3-ry682tkyiqk.js" async=""></script>
    <script src="/_next/static/chunks/3oh00mkbkq8u6.js" async=""></script>
    <script src="/_next/static/chunks/44sbnxvltlcyy.js" async=""></script>
    <script src="/_next/static/chunks/02thki4p6-q9o.js" async=""></script>
    <script src="/_next/static/chunks/2xcgb3osv6l_b.js" async=""></script>
    <title>Tea shop</title>
    <script src="/_next/static/chunks/0cz1d0mv5g_q7.js" nomodule=""></script>
  </head>
  <body>
    <div hidden="">
      <!--$-->
      <!--/$-->
    </div>
    <nav><a href="/">Home</a> <a href="/teas">Teas</a></nav>
    <!--&-->
    <section>
      <nav><a href="/teas/green">Green tea</a> <a href="/teas/mint">Mint tea</a></nav>
      <p>Cups brewed: <!-- -->0<!-- --> <button>Brew a cup</button></p>
      <!--&-->
      <div>
        <!--$?-->
        <template id="B:0"></template>
        <p>Loading the tea…</p>
        <!--/$-->
        <label>Tasting notes <input value=""></label>
      </div>
      <!--/&-->
    </section>
    <!--/&-->
    <script>…</script>
    <script id="_R_">…</script>
    <script src="/_next/static/chunks/1x6obpmlu1_c2.js" async=""></script>
    <div hidden="" id="S:0">
      <!--&-->
      <template id="P:1"></template>
      <!--$-->
      <!--/$-->
      <!--/&-->
    </div>
    <script>…</script>
    <script>…</script>
    <script>…</script>
    <script>…</script>
    <script src="/_next/static/chunks/0cz1d0mv5g_q7.js" nomodule=""></script>
    <div hidden="" id="S:1">
      <main>
        <h1>Tea of the day</h1>
        <p>Mint tea, brewed at 9.</p>
      </main>
    </div>
    <script>…</script>
    <script>…</script>
  </body>
</html>

app/teas/loading.tsx, shown first, returns Loading the tea… on line 2. In app/teas/today/page.tsx, line 4 calls connection(), which tells Next.js to make this page for each request, and line 6 waits a second, as a slow database would. The Terminal tab lists ◐ /teas/today: a static shell made during the build, and the page streamed in for each request.

The Network tab is open on /teas/today, and shows the HTML in the order it arrived. Inside the tea layout's <section> comes the template's <div>, and inside it, <p>Loading the tea…</p>, then the notes' <label>. So the loading state sits inside the template, and the template inside the layout: the menu, the counter and the notes box show at once, and only the page waits. The page itself arrives further down, in a hidden <div>, and takes the fallback's place. error.tsx and not-found.tsx add nothing to the HTML: nothing broke, and nothing was missing.

Two rules follow from the order. First, error.tsx catches errors from what's inside it, never from the layout.tsx or template.tsx of its own folder; an error there goes to the error.tsx of the folder above. Second, the layout and the template stay on the screen around the loading, error and not-found screens of their folder, so the menu keeps working while the page part waits or fails. Error handling and Not found, forbidden and unauthorized show those screens.

Folders inside folders

Each folder's files nest inside the folder above. On /teas/green, the root layout from app wraps everything from app/teas, and the tea files wrap the page from app/teas/green. Written by hand, the tree Next.js builds for that address in the full tea folder is roughly this:

What Next.js builds for /teas/green, written by handJSX
<RootLayout>
  <TeasLayout>
    <TeasTemplate key="green">
      <ErrorBoundary fallback={<TeaError />}>
        <Suspense fallback={<Loading />}>
          <NotFoundBoundary fallback={<TeaNotFound />}>
            <GreenTeaPage />
          </NotFoundBoundary>
        </Suspense>
      </ErrorBoundary>
    </TeasTemplate>
  </TeasLayout>
</RootLayout>

Line 1 is the root layout, and line 2 the tea layout. Line 3 is the template, with a key: React makes a new component whenever its key changes, and Next.js takes the key from the folder below the template, here green. Lines 4 to 6 are the three boundaries from error.tsx, loading.tsx and not-found.tsx. Line 7 is the page. This is a sketch to read, not code you write: in Next.js's code, the three boundaries are called ErrorBoundary, LoadingBoundary and HTTPAccessFallbackBoundary.

A layout stays; a template starts again

Now the difference you came for. Clicks need a browser with the page's JavaScript running, so this recording was made in real Chrome. The recorder opened /teas/green, pressed Brew a cup twice, typed Grassy into the tasting notes, clicked Mint tea, then clicked Green tea. Before you open the Steps tab, guess what the counter and the notes show after each click.

The counter in the layout, the notes in the templateNext.js
app/teas/green/mint/
app/teas/template.tsx
import NotesBox from "./notes-box"; export default function TeasTemplate({ children }: { children: React.ReactNode }) {  return (    <div>      {children}      <NotesBox />    </div>  );}
Recorded from Next.js 16.4.3

Each step was taken in real Chrome against next start. Pick one to see the page after it.

localhost:3000/teas/mintTea shop
Home Teas
Green tea Mint tea

Cups brewed: 2 Brew a cup

Mint tea

Cool and sweet. $3 a box.

Focus
the link “Mint tea”
Scrolled
0 px down

No requests during this step: the page already had what it needed

The Steps tab is open on step 5, right after the click on Mint tea. Cups brewed: 2: the tea layout stayed on the screen, so its BrewCounter kept its state, as in the layouts lesson. But the tasting notes are empty. Mint tea is a new page under the template, so Next.js made a new copy of the template for it, with a new NotesBox and a new, empty state. The click made no request at all: the Mint tea page had been prefetched, loaded in the background, when its link appeared.

Now pick step 6, back on Green tea. The notes say Grassy again. Next.js didn't throw Green tea's copy away when you left. With Cache Components on, as in new projects, it hides the page you leave with React's Activity, state and all, and shows it again when you come back. At each level of folders, it keeps the page on the screen plus up to two you left: in bfcache-state-manager.ts, MAX_BF_CACHE_ENTRIES is 3 with Cache Components on, counting the visible one, and 1 without. The template's copy for Green tea is part of what it kept. So a template doesn't forget everything on each visit: each page under it has its own copy, and a page you return to soon gets its copy back.

After the click on Mint tea. One teas/layout.tsx with Cups brewed: 2 wraps two copies of teas/template.tsx. The Green tea copy, with the notes Grassy, is kept hidden. The Mint tea copy, with empty notes, is on the screen.teas/layout.tsxCups brewed: 2template.tsxGreen teanotes: Grassytemplate.tsxMint teanotes: (empty)kept hiddenon the screen
After the click on Mint tea: one tea layout, still at Cups brewed: 2, and one template copy for each tea page. Mint tea's copy is new, with empty notes. Green tea's copy, with Grassy, is kept hidden, and comes back with the next click on Green tea.

Which navigations make a new copy? The template's key comes from the folder right below it, so a new copy comes when that part of the address changes: /teas to /teas/green, or /teas/green to /teas/mint. The docs add two cases this recording doesn't show: moving deeper below that folder doesn't make a new copy of a template higher up, and a change in the query, the part after ?, doesn't either.

When a template beats a layout

A new copy also means its Effects run again. That's the other reason to use a template: code that should run each time a page shows, like logging a page view. Here a small Client Component logs a view in an Effect, and shows how many it logged. app/teas/views.ts stands in for an analytics service:

app/teas/template.tsx with the view loggerTSX
import ViewLogger from "./view-logger";

export default function TeasTemplate({ children }: { children: React.ReactNode }) {
  return (
    <div>
      {children}
      <ViewLogger />
    </div>
  );
}

Line 1 imports ViewLogger, and line 7 puts it under each tea page. Both versions below use the same ViewLogger: once in the template, once in the layout. Each was clicked through in Chrome: Green tea, Mint tea, Green tea, Home, then Teas. Guess the counts first.

Playground: how many views does each one log?
The tea pages, with ViewLogger hereNext.js
app/teas/green/mint/
app/teas/template.tsx
import ViewLogger from "./view-logger"; export default function TeasTemplate({ children }: { children: React.ReactNode }) {  return (    <div>      {children}      <ViewLogger />    </div>  );}
Recorded from Next.js 16.4.3

Each step was taken in real Chrome against next start. Pick one to see the page after it.

localhost:3000/teas/greenTea shop
Home Teas
Green tea Mint tea
Green tea

Light and fresh. $4 a box.

Views logged: 3

Focus
the link “Green tea”
Scrolled
0 px down

No requests during this step: the page already had what it needed

Try it yourself
In the template

The template puts ViewLogger under each tea page, on line 7. Every tea page that shows runs its Effect: 1 on Green tea, 2 on Mint tea, 3 back on Green tea, and 4 on Teas.

Each version was built with next build from Next.js 16.4.3, run with next start, and clicked through in real Chrome: open /teas/green, click Mint tea, click Green tea, click Home, then click Teas. Pick a step to see the page after it. Reset goes back to the first version.

In the template, every tea page that shows runs the Effect: Views logged: 1, 2, 3, then 4 on Teas. Even Green tea's copy, shown again from hiding, ran it again: React runs a hidden component's Effects again when it shows. In the layout, the count stays at 1 while you move between teas, because the layout never left the screen. It only logs 2 after Home and Teas, when the whole tea layout was hidden and shown again.

Next.js's docs name three reasons to pick a template:

  • State that belongs to one page. An input or a form that should start empty on each page, like the tasting notes.
  • Effects that run on each page. Logging a view, or anything else that must happen each time a page shows.
  • A loading state on every navigation. The docs say a Suspense in a layout shows its fallback only the first time, and one in a template shows it again on each navigation, because the template is new.

Everything else belongs in a layout. A template costs a new copy on each page, so use one only when you want that.

default.tsx: a first look

One more special file belongs in the hierarchy, though it only matters with slots. A slot is a folder whose name starts with @, like app/@offer. It's a second place for a page, beside children: the layout gets it as a prop named after the folder. Slots are part of parallel routes, which have a lesson of their own: Parallel routes. Here the shop shows a special offer above the home page:

An offer slot with a default.tsxNext.js
app/@offer/teas/
app/@offer/default.tsx
export default function OfferDefault() {  return null;}
Recorded from Next.js 16.4.3

Each step was taken in real Chrome against next start. Pick one to see the page after it.

localhost:3000/
Home Teas
Today only: 2 boxes for $6.
Tea shop

Fresh tea, sent to your door.

Focus
nothing: the page itself
Scrolled
0 px down

Requests the page made during this step (5), without the files it loaded

  1. GET/200a whole page
  2. GET/200text/x-component
    rsc
    1
    next-router-prefetch
    1
    next-router-segment-prefetch
    /_tree
    next-url
    /
  3. GET/teas200text/x-component
    rsc
    1
    next-router-prefetch
    1
    next-router-segment-prefetch
    /_tree
    next-url
    /
  4. GET/teas200text/x-component
    rsc
    1
    next-router-prefetch
    1
    next-router-segment-prefetch
    /teas/__PAGE__
    next-url
    /
  5. GET/teas200text/x-component
    rsc
    1
    next-router-prefetch
    1
    next-router-segment-prefetch
    /@offer/__DEFAULT__
    next-url
    /

In app/layout.tsx, line 3 takes offer next to children, and line 10 puts it above the page. app/@offer/page.tsx is the offer for /. But the slot has no page for /teas. app/@offer/default.tsx, the file shown first, is what it shows then: line 2 returns null, nothing.

The Steps tab shows when that happens. Step 1 opens /, with the offer. Step 2 clicks Teas, and the offer is still there: on a click, Next.js keeps showing the slot's last page. Step 4 opens /teas as a fresh page load, and the offer is gone. With nothing to keep, Next.js rendered default.tsx. The Network tab's /teas shows the same: no <aside>.

Two browser windows at /teas. Left, after clicking Teas on the home page: the offer, Today only: 2 boxes for $6, is still above Our teas. Right, after opening /teas directly: no offer, because @offer/default.tsx returned nothing.After a click on Teas/teasToday only: 2 boxes for $6.Our teasthe slot keeps its last pageAfter opening /teas/teas(nothing from @offer)Our teasthe slot shows default.tsx
The @offer slot has a page only for /. After a click on Teas, Next.js keeps showing the slot's last page. On a fresh load of /teas it has nothing to keep, so it renders @offer/default.tsx.

Without default.tsx, Next.js 16.4.3 doesn't build at all:

The offer slot without default.tsx (a build error on purpose)Next.js
app/@offer/teas/
app/layout.tsx
import Link from "next/link"; export default function RootLayout({ children, offer }: LayoutProps<"/">) {  return (    <html lang="en">      <body>        <nav>          <Link href="/">Home</Link> <Link href="/teas">Teas</Link>        </nav>        {offer}        {children}      </body>    </html>  );}
next build failed · Next.js 16.4.3
$ next build▲ Next.js 16.4.3 (Turbopack)- Cache Components enabled- Partial Prefetching enabled   Creating an optimized production build ...⚠ Strict route matching is enabled by default. This validation indicates a bug in your app's route structure, but you can temporarily restore loose route matching by setting `deprecated.looseRouteMatching` to `true` in your Next.js config. > Build error occurredError: Turbopack build failed with 2 errors:./app/layout.tsxError: Parallel route slots cannot render the same URLsThe following layouts have parallel route slots that cannot render the same URLs:app/layout.tsx- /teas is missing a matching page or default.tsx in @offer Every URL matched by one slot must have a matching page or default.tsx in every sibling slot. ./app/teas/page.tsxError: Unmatched app pagesThe following page files do not match any complete route:- app/teas/page.tsx Every page must be part of at least one complete route. Add matching pages or default files for the sibling parallel route slots, or remove the unreachable pages.     at ignore-listed frames

The build stops with Parallel route slots cannot render the same URLs, and names the problem: /teas is missing a matching page or default.tsx in @offer. So this named slot needs a default.tsx: on a fresh load of /teas, @offer has no page and no last page to keep. (children is a slot too, without the @. The docs page for default.js still describes the older behavior for it, a 404, but Next.js 16.4.3's strict route matching stops the build when children has no default.tsx for an address its sibling slots can show. Parallel routes records both.)

Reading the tree Next.js builds

The sketch earlier was written by hand. You can read the real thing in Next.js's source, at the release every example here was built with. Two files do the work. First, create-component-tree.tsx reads each folder's special files: layout, template, error, loading, not-found, and two more for access errors, forbidden and unauthorized. A folder without a template gets React's Fragment in its place, which renders only its children (lines 218 to 226). Then it hands them to a component called LayoutRouter, which fills the layout's children (lines 696 to 724).

Second, LayoutRouter, in layout-router.tsx, nests them. Simplified, with the props and the development-only parts left out, it renders this for the folder below a layout:

What layout-router.tsx renders, simplified from Next.js 16.4.3JSX
<Activity key={stateKey} mode={stateKey === activeStateKey ? "visible" : "hidden"}>
  <TemplateContext.Provider key={stateKey} value={
    <ErrorBoundary errorComponent={error}>
      <LoadingBoundary loading={parentLoadingData}>
        <HTTPAccessFallbackBoundary notFound={notFound} forbidden={forbidden} unauthorized={unauthorized}>
          <RedirectBoundary>
            <InnerLayoutRouter tree={tree} />
          </RedirectBoundary>
        </HTTPAccessFallbackBoundary>
      </LoadingBoundary>
    </ErrorBoundary>
  }>
    {template}
  </TemplateContext.Provider>
</Activity>

In plain words, from the outside in:

  1. Line 1: with Cache Components on, an Activity for each page Next.js keeps, visible or hidden. This is what kept Green tea's notes.
  2. Line 2: the template's place, with the key from the folder below. Your template gets lines 3 to 11 as its children; line 13 is your template.
  3. Line 3: an error boundary with your error.tsx.
  4. Line 4: a loading boundary with your loading.tsx.
  5. Line 5: one boundary for not-found.tsx, forbidden.tsx and unauthorized.tsx.
  6. Line 6: a boundary for redirects. It catches a redirect() that reaches the browser while the page renders, and moves the router to the new address (Redirects covers the function).
  7. Line 7: the folder below, with its own layout and its own LayoutRouter, all the way down to the page.

That's the whole hierarchy: the order of the boundaries in this one component. How a route becomes a React tree, in the course's last stage, reads these files properly.

Layout or template for the tea shop?

Each row asks one question of both files:

layout.tsx and template.tsx
Questionlayout.tsxtemplate.tsx
How many copies are there?One, for every page under it.One for each page under it.
What happens on a click to another page under it?It stays, with its state.A new copy for the new page, with fresh state.
What happens when you come back to a page you left?It's the same one it always was.Its old copy comes back, with its state, if Next.js kept it hidden: with Cache Components on, up to two pages you left, beside the one on the screen.
When do Effects inside it run?Once, and again only after the whole layout was hidden and shown.Each time a page under it shows.
What is it good for?Menus, headers, and state the pages share.State that belongs to one page, like a notes box, and logging each page view.

Sort the tea shop's parts: which file should hold each one?

Layout or template?
  • The tea menu at the top of every tea page.
  • A cup counter that keeps counting as the shopper moves between teas.
  • A tasting notes box that should be empty on each new tea.
  • An Effect that logs a page view each time a tea page shows.
  • A small cart summary that should keep what the shopper added.
  • A "Was this page helpful?" form whose answer belongs to one page.
Try it yourself
0 of 6 correct

Sort each part of the tea pages: does it belong in the layout, or in a template?

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common mix-ups

  • "A template replaces the layout." No. It goes inside the layout of its folder, and a folder can have both, as the tea folder does.
  • "A template starts fresh on every visit." No. Each page under it gets its own copy. Coming back to a page you left soon brings its copy back, with its state.
  • "A template has to be a Client Component." No. Like a layout, it starts as a Server Component; the state lives in the Client Components it renders.
  • "error.tsx catches errors in the layout beside it." No. The layout and the template are outside it. The error.tsx of the folder above catches those.
  • "The loading state replaces the whole folder." No. It shows inside the layout and the template; only the page part waits.
  • "default.tsx is the page for a folder." No. That's page.tsx. default.tsx stands in for a slot that has no page for the address.

Practice exercises

These exercises are about Next.js projects, which can't run inside this page.

Exercise 1 · Warm-upPut the files in order

Write these six special files of one folder from the outside in.

Starter codeText
page.tsx
error.tsx
layout.tsx
not-found.tsx
template.tsx
loading.tsx

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upRead the first HTML

    This is app/teas/today/page.tsx in the full tea folder. In the first HTML of /teas/today, what shows where the page will go?

    Starter codeTSX
    import { connection } from "next/server";
    
    export default async function TodayPage() {
      await connection();
      // Wait a moment, as a real database would, so the recording can catch the loading state.
      await new Promise((resolve) => setTimeout(resolve, 1000));
      return (
        <main>
          <h1>Tea of the day</h1>
          <p>Mint tea, brewed at 9.</p>
        </main>
      );
    }
    

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticePredict the counter

      On Green tea, you press Brew a cup twice, then click Mint tea. With this template and the counter in the tea layout, what does the counter say on Mint tea?

      Starter codeTSX
      import NotesBox from "./notes-box";
      
      export default function TeasTemplate({ children }: { children: React.ReactNode }) {
        return (
          <div>
            {children}
            <NotesBox />
          </div>
        );
      }
      

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticePredict the notes

        Then you type Grassy into the notes on Green tea, click Mint tea, and click Green tea again. What do the notes say?

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeCount the logged views

          With ViewLogger in the template, you open Green tea, then click Mint tea, Green tea, Home and Teas. What does the page say on Teas?

          Starter codeTSX
          import ViewLogger from "./view-logger";
          
          export default function TeasTemplate({ children }: { children: React.ReactNode }) {
            return (
              <div>
                {children}
                <ViewLogger />
              </div>
            );
          }
          

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeFix the build

            The shop's build fails with /teas is missing a matching page or default.tsx in @offer. Which file is missing? Write it so the offer shows nothing on /teas.

            Starter codeTSX
            // app/@offer/default.tsx
            export default function OfferDefault() {
              // What should the offer slot show on pages it has no page.tsx for?
            }

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              For each question, find the file in the nesting order, and ask whether a new copy of it was made.

              The Templates quiz · 7 questionsScore: first tries count
              1. Question 1 of 7In one folder, which file sits outside error.tsx, so error.tsx can't catch what breaks in it?

                Choose an answer to see the explanation.

              2. Question 2 of 7The recorder typed Grassy into the template's notes on Green tea, then clicked Mint tea. What does the notes box show?

                Read the code, then predictTSX
                import NotesBox from "./notes-box";
                
                export default function TeasTemplate({ children }: { children: React.ReactNode }) {
                  return (
                    <div>
                      {children}
                      <NotesBox />
                    </div>
                  );
                }
                

                Choose an answer to see the explanation.

              3. Question 3 of 7Then the recorder clicked Green tea again. What do the notes show now?

                Choose an answer to see the explanation.

              4. Question 4 of 7ViewLogger logs a view in an Effect. In the template, the recording counts 1, 2, 3 over Green tea, Mint tea and Green tea. What does it count in the layout?

                Choose an answer to see the explanation.

              5. Question 5 of 7What does Next.js render inside {children} of app/teas/template.tsx on /teas/today, before the page is ready?

                Choose an answer to see the explanation.

              6. Question 6 of 7This is app/@offer/default.tsx. When does Next.js render it?

                Read the code, then predictTSX
                export default function OfferDefault() {
                  return null;
                }
                

                Choose an answer to see the explanation.

              7. Question 7 of 7Without app/@offer/default.tsx, what happens?

                Choose an answer to see the explanation.

              Key takeaways

              • In one folder, the special files nest in this order: layout, template, error, loading, not-found, page. A folder below nests inside the folder above.
              • The layout and the template stay around the loading, error and not-found screens; error.tsx never catches errors from the layout or template beside it.
              • A layout is one copy for all its pages. A template is a new copy for each page under it, so state inside it starts fresh on a new page.
              • With Cache Components on, a page you leave is kept hidden with its state, template copy included, and comes back as it was.
              • Effects in a template run each time a page shows. Use a template for per-page state and per-page Effects; use a layout for the rest.
              • A named slot, a folder starting with @ like @offer, shows its default.tsx on a fresh load of an address it has no page for. Without one, this shop's build stopped.

              Remember the one-liner.
              Layout, template, error, loading, not-found, page: a layout stays for all its pages, and a template is made again for each one.

              Coming next: Server Components in Next.js. It starts the stage about where your code runs, with the kind of component every layout, template and page starts as.

              CompleteFrontend Clear concepts. Working examples.