Master DRY in Next.js with Layouts
Tags: nextjs, fullstack, typescript, javascript
Published: 2024-05-14 14:25:48

*This is my course on Next.js called Bite-Sized Next.js, where we learn core Next.js concepts in 5 minutes or less. I originally published this lesson on my [blog](https://jaydevm.hashnode.dev/master-dry-in-nextjs-with-layouts).*

Welcome back! Now that you've learned the [essentials of pages](https://jaydevm.hashnode.dev/bite-sized-nextjs-part-3-basic-routing-and-pages) in Next.js, it’s time to delve deeper and explore some of the more advanced features concerning pages. While I am calling them advanced ideas, you will definitely need to know them to build a truly well-crafted Next.js app.

## Layouts

Imagine if you needed to figure out if a user can access a particular page in your app, and you wrote this code:

```typescript
let canAccessPage: boolean;

if (!user.isLoggedIn) {
    canAccessPage = false;
}

canAccessPage = user.roles.includes(requiredRole);
```

You're proud of your solution, and you should be! Then, every time you need to check access, you copy and paste those lines everywhere. That wouldn’t be so smart anymore, would it? Intuitively, you would define a function to encapsulate the logic:

```typescript
function checkAccess(user: User, requiredRole: string): boolean {
    return user.isLoggedIn && user.roles.includes(requiredRole);
}
```

For some reason Don’t Repeat Yourself is exclusively discussed in the context of code. Meanwhile I see lots of people breaking this guidance when it comes to markup.

Fortunately Next.js has a DRY answer for HTML: layouts! Layouts allow you to neatly encapsulate your markup, just like the function definition above does for checking a user’s access.

Essentially, layouts are just like any other page component in Next.js, but they accept a special `children` argument. This is where your child page will be populated in the layout.

### A simple example

For example, if you were building a dashboard, you could use a layout like this:

```typescript
export default function DashboardLayout({
  children, // will be a page or nested layout
}: {
  children: React.ReactNode;
}) {
  return (
    <main>
      <h1>This is the layout</h1>
      <section>
        {/* Include shared UI here e.g. a header or sidebar */}
        <nav></nav>
        {children}
      </section>
    </main>
  );
}

```

Your child page could be something like this:

```typescript
export default function MyDashboard() {
  return <h2>This is my dashboard</h2>
}
```

And this would be the final rendering:

![example of using next.js layout](https://cdn.hashnode.com/res/hashnode/image/upload/v1715694694773/fe47eddd-c415-42e5-a7ce-b06a4c40db07.png)

### Where should I use layouts?

Think about all of the elements that are the same across your app. These are all great candidates for incorporating into your layout! Navigation headers, sidebars, and footers are probably the most common components that developers put into layouts.

The Next.js website itself has a common header and footer across many pages. I’ve highlighted them in blue below:

![next.js layout candidate sections](https://cdn.hashnode.com/res/hashnode/image/upload/v1715694705217/258ab72d-6676-4888-b5d5-b28a4cfccc35.png)

### Using multiple layouts

Just like pages, layouts can be nested inside each other. When Next.js traverses your app hierarchy, it will make a note of all the layouts it finds along the path to each `page.tsx` file. Then all of those layouts will be stacked together to produce your completed markup. The Next.js docs have a [nice visual](https://nextjs.org/docs/app/building-your-application/routing/layouts-and-templates#nesting-layouts) of this process.

![next.js layout rendering hierarchy](https://cdn.hashnode.com/res/hashnode/image/upload/v1715694712211/4d893373-467c-462b-9334-17ec6b218352.png)

### Other stuff to know

There are a couple other important things to know about layouts:

1. You **must** define a root layout directly under the `app/` folder, and it **must** contain the `html` and `body` tags. Something like this would suffice:
    

```typescript
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* Layout UI */}
        <main>{children}</main>
      </body>
    </html>
  )
}
```

1. You can have a `layout.tsx` and a `page.tsx` in the same folder, and the page will inherit from the layout.
    

## Templates

Templates are a special case of layouts. They are almost identical in terms of behavior, but the notable difference is that templates do not persist local state in between renderings. Think of templates as layouts with short-term memory problems. 🙂

```typescript
export default function Template({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}
```

### Use cases

Why would you want to use templates? There are certain situations where you want the page to render from scratch. Here are a couple scenarios:

1. You created a cool animation that runs with `useEffect` when a page loads. You always want the animation to play, no matter how many times the user has already navigated there.
    
2. You have a client-side payment form that leverages `useState` and collects credit card numbers. If the user navigates away, you want the form to be wiped clean.
    

### How layouts and templates work together

With templates in the mix, understanding the order in which layouts, templates, and pages will render can be a little complicated. It goes like this:

1. Start at the top-level source folder (i.e. `app`)
    
2. Render the layout (if present), then the template (if present)
    
3. Have we reached the page we are looking for?
    
    1. Yes —&gt; render the page and finish
        
    2. No —&gt; move to the next folder down the hierarchy and repeat step (2)
        

### Try to keep it simple

Maybe you’re wondering: if I have a layout within a template, will that layout persist between renders? The answer is no! In Next.js, you need to be mindful of how you organize things, especially state-holding components. If you find yourself nesting layouts and templates too deeply, you may want to simplify your layout hierarchy.

In this aspect, layout inheritance mirrors OOP (class) based inheritance. It’s a useful feature up to the point where it becomes too complex to understand. That’s when the effort of refactoring becomes worth the cost.

## Conclusion

In this lesson, we've explored the powerful concepts of layouts and templates, tools that help us adhere to the DRY principle not just in our code but also in our markup. Understanding and implementing layouts will give your app a more consistent look and feel and help you manage page hierarchies effectively.

Next, we will delve into advanced routing techniques, helping you to create more dynamic Next.js applications. [Subscribe](https://jaydevm.hashnode.dev/newsletter) to get the next tutorial!