How to Share UI Across Pages with Nested Layouts

Stop repeating a sidebar or nav bar in every page. Use a nested layout to share UI across a group of routes in the Next.js App Router.

6 min read

You can share UI across pages in the Next.js App Router by placing that UI inside a nested layout instead of copying it into every route file. This is how you avoid repeating a sidebar or nav bar in every page.

Say a dashboard section needs the same sidebar on every page inside it. Add one layout file to the dashboard folder and every route below it gets the sidebar automatically, with no import needed in the page files themselves.

texttext
app/
  dashboard/
    layout.tsx        (shared UI for every route below)
    page.tsx           (served at /dashboard)
    settings/
      page.tsx          (served at /dashboard/settings)

Both page files render inside this same layout without importing it or repeating its markup, because the App Router applies a layout to every route nested under its folder.

App.tsxApp.tsx
// app/dashboard/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="dashboard-shell">
      <aside>Dashboard sidebar</aside>
      <main>{children}</main>
    </div>
  );
}

Open the dashboard page and the settings page in the browser and the sidebar appears on both, even though neither page file mentions it. The layout supplies it once for the whole folder.

Why this beats repeating the UI in every page

Copying a sidebar into every page file means updating every file when the design changes, and it means the browser treats the sidebar as new content on every navigation. A shared layout avoids both problems at once.

When a reader clicks from the dashboard page to the settings page, Next.js keeps the layout mounted and only swaps the content inside main. The sidebar does not flicker or lose its scroll position, because it never leaves the tree during that navigation.

Fetching data for the shared UI

A layout cannot receive data from the page it wraps, so if the sidebar needs its own data, fetch it inside the layout directly instead of trying to pass it down from a page.

App.tsxApp.tsx
// app/dashboard/layout.tsx
import { getNavLinks } from "@/lib/nav";
export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
  const links = await getNavLinks();
  return (
    <div className="dashboard-shell">
      <aside>{links.length} nav links loaded</aside>
      <main>{children}</main>
    </div>
  );
}

If the page below the layout needs the same data, call getNavLinks again inside the page. Next.js automatically dedupes an identical fetch request made in both places during one render, so this does not trigger a second network round trip. For a database call instead of fetch, wrap the function in React's cache so both places share one result, as shown in Passing Data Between Layouts and Pages in Next.js.

A limit worth knowing

A layout does not re-render on navigation, so it cannot read the query string, which would go stale the moment the URL changes without a re-render to catch it. If the shared UI needs to react to a query string, read it inside a client component using the useSearchParams hook, covered in Next.js params vs searchParams: How to Read URL Parameters, or move that piece into the page itself, which does receive it directly.

Rune AI

Rune AI

Key Insights

  • Add a layout to a folder to share its UI with every route inside that folder.
  • A layout stays mounted across navigation inside the same segment, so it does not re-render.
  • Layouts and the pages they wrap fetch their own data independently.
  • Next.js dedupes an identical fetch call made by both a layout and a page.
  • A layout cannot read the query string because it does not re-render when it changes.
RunePowered by Rune AI

Frequently Asked Questions

Do I need a layout for every folder?

No. Add a layout only to the folder where the shared UI should start applying. Every route below that folder inherits it automatically.

Can a page pass data up into the layout that wraps it?

No. A layout cannot read data from the page it wraps. Fetch what the layout needs directly inside the layout instead.

Does clicking a link inside a shared layout reload that layout?

No. The layout stays mounted and only the page content below it updates, which is what makes it feel instant compared to repeating the UI in every page.

Conclusion

A nested layout is the App Router's answer to shared UI. Put a layout file in the folder where the shared UI should start, and every route inside that folder gets it without repeating a single line of markup.