Difference between layouts and templates in Next.js
Layouts are not templates!
Introduction
Templates and layouts are often used interchangeably without regard for the use cases and differences between the two concepts. This article explains the difference between templates and layouts in Next.js and the appropriate use cases for templates and layouts.
Prerequisites
To get a good read of this article, you should understand the basics of Next.js.
Difference between layouts and templates
Layouts in Next.js
"A layout is UI shared between multiple pages."; Layout is a way of abstracting UI common to multiple pages in the same route segment or even the entire application into a component; for example, a UI element like a footer can be repetitive in the whole application. This form of UI, common to the entire application and not a specific page, is abstracted into the root layout.
What to note about the layout:
Navigating between different pages that share the same layout will not cause the layout component to re-render.
On navigation, the state in the layout is still preserved and remains fully interactive.
Templates in Next.js
Templates are synonymous with layouts; they are also shared UI that is repetitive on multiple pages. However, the difference between templates and layouts is that :
Layouts preserve state and don't re-render on navigation between routes.
Templates don't do this; they re-render on navigation between page routes and create a new instance for each of its children.
Some use cases of templates:
Enter and exit animations. This kind of animation in CSS requires re-rendering for it to occur; layouts aren't the right fit for them.
Features relying on the useEffect function. Like logging page views.
To change the default framework behavior. For example, suspense boundaries inside layouts show the fallback only once when the layout is loaded and not when switching pages. For templates, the fallback gets shown on each navigation due to the template re-rendering.
Live implementation
Let's see a live example of this difference.
I created a simple next.js app with a single page. The page1 has an additional route nested in it.
Here is the folder structure:
We created a layout for the 'page1' route segment, which wraps all child elements, including nested routes.
"use client";
//layout logic
import Link from "next/link";
import { useEffect } from "react";
export default function page1Layout({
children, // will be a page or nested layout
}) {
useEffect(() => {
console.log("layout mounted");
}, []);
return (
<section
className="w-full h-32 items-center justify-between
p-4 flex list-none first-letter first-letter
bg-gradient-to-tl from-cyan-500 to-gray-950 bg-slate-600 "
>
<div
className=" gap-6 items-center justify-center h-16 cursor-pointer
font-nunito text-white font-bold flex"
>
<Link href="/page1/inner">
<li className="navlink">innerworld</li>
</Link>
<Link href="../page1">
<li className="navlink">page1</li>
</Link>
</div>
{children}
</section>
);
}
What we have here is a simple mock navigation bar. It switches from the page (page1) to its nested page (inner). We also use the useEffect hook to log a string when the layout component mounts. This logic demonstrates that the layout would persist even on page change.
Here's how the navigation bar looks:
Observing the console, you'll notice that the string only gets logged once when the component is first mounted. However, on subsequent page navigations, nothing is logged because the layout is not re-rendered.
console(string logged only when component mounts):
If a feature you want to add requires layout re-rendering, you best use a template. Here's our implementation:
"use client";
//template logic
import Link from "next/link";
import { useEffect } from "react";
export default function Template({
children,
}) {
useEffect(() => {
console.log("layout mounted");
}, []);
return (
<section
className="w-full h-32 items-center justify-between
p-4 flex list-none first-letter first-letter
bg-gradient-to-tl from-cyan-500 to-gray-950 bg-slate-600 "
>
<div
className=" gap-6 items-center justify-center h-16 cursor-pointer
font-nunito text-white font-bold flex"
>
<Link href="/page1/inner">
<li className="navlink">innerworld</li>
</Link>
<Link href="../page1">
<li className="navlink">page1</li>
</Link>
</div>
{children}
</section>
);
}
We created a new file called "Template.jsx" in our route segment and replaced it with the navigation logic from the previous layout. Templates and layouts follow the same pattern. However, now that we've switched the navigation logic to a template, the template undergoes re-rendering every time there's page navigation between the two pages that share the same template.
console(string logged multiple times on page switch):
Final version:
Click the button to view the navigation.
Conclusion
That’s all, folks. I hope you learned a few. If you followed through, you should now understand the difference between layouts and templates.
You can read more in the additional resources section below. Follow me for more content like this🚀🚀🚀🚀🚀.