How to Use Multiple Layouts in Next.js


What would be the best way to incorporate multiple layouts in our Next.js application?

Define Layouts

Suppose I have two layouts, Layout1 and Layout2, that I want rendered, depending on the page.

Layout1 might look something like this.

// layouts/Layout1.jsx
const Layout1 = ({ children }) => {
  return <div className="layout1">{children}</div>;
};
export default Layout1;

And Layout2 is a drastically different layout.

// layouts/Layout2.jsx
const Layout2 = ({ children }) => {
  return <div className="layout2">{children}</div>;
};
export default Layout2;

Example Usage

I considered changing layouts based on routes (i.e. all pages/layout1/* use Layout1), but it yielded suboptimal render performance.

I found that the easiest way to change layouts is to define it on the page level.

// pages/home.jsx
const Home = () => <div>Home</div>;
Home.layout = "L1";
export default Home;
// pages/about.jsx
const About = () => <div>About</div>;
About.layout = "L2";
export default About;

Then, inside our _app.jsx, we can handle all required imports.

// pages/_app.jsx
import Layout1 from "@/layouts/Layout1";
import Layout2 from "@/layouts/Layout2";
const layouts = {
  L1: Layout1,
  L2: Layout2,
};
const App = ({ Component, pageProps }) => {
  const Layout = layouts[Component.layout] || ((children) => <>{children}</>);
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  );
};
export default App;

Nested Layouts

The provided solution will work very nicely if we don’t require any nested layouts.

If we need multiple, nested layouts, instead of returning a string identifying the layout a page needs, we can return a function of the expected layout.

// pages/home.jsx
import Layout1 from "@/layouts/Layout1";
import Layout2 from "@/layouts/Layout2";
Home.layout = (page) => (
  <Layout1>
    <Layout2>{page}</Layout2>
  </Layout1>
);
// pages/about.jsx
import Layout2 from "@/layouts/Layout2";
import Layout1 from "@/layouts/Layout1";
About.layout = (page) => (
  <Layout2>
    <Layout1>{page}</Layout1>
  </Layout2>
);

Inside _app.jsx, we can change how we render our components.

// pages/_app.jsx
const pageLayout = Component.layout || ((page) => page);
return pageLayout(<Component {...pageProps} />);