Passing Data Between Layouts and Pages in Next.js

Layouts cannot pass data to the pages they wrap, and pages cannot pass data up to a layout. Learn the real patterns for sharing data between them.

6 min read

A Next.js layout has no channel for sending data down to the page it wraps, beyond rendering that page as its children. A page has no channel for sending data up to its layout either. Each one gets its own props from Next.js and fetches its own data.

This surprises developers coming from a component tree where a parent can pass any prop it wants to a child. A layout's only real prop is children, so a common data-sharing plan, like reading a value in the page and expecting the layout above it to see that value, does not work.

What each side actually receives

Both a layout and the page it wraps receive params independently when the route includes a dynamic segment, and both must await it before reading a value.

App.tsxApp.tsx
// app/dashboard/[team]/layout.tsx
export default async function TeamLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ team: string }>;
}) {
  const { team } = await params;
  return <div data-team={team}>{children}</div>;
}

The page at the same route receives the identical team value through its own params, without the layout passing anything. Next.js resolves the URL once and hands the matching value to every file in that segment.

Only a page receives searchParams. A layout does not rerender when the query string changes, so Next.js never gives it a query string value at all. If shared UI in a layout needs to react to one, that piece has to move into a client component that reads the current URL with a client-side hook instead.

Sharing one data fetch between a layout and a page

When a layout and a page both need the same data, such as the current user, call the same function in both places instead of trying to send it from one to the other.

App.tsxApp.tsx
// lib/user.ts
import { cache } from "react";
 
export const getUser = cache(async (id: string) => {
  const res = await fetch(`https://api.example.com/users/${id}`);
  return res.json();
});

Wrapping the function in cache means that if the layout and the page both call it with the same user ID during the same request, only one network call happens. Plain fetch calls are deduped automatically by Next.js even without cache, but cache extends that same deduping to a database client or any other async function.

What does not exist

There is no context provider that Next.js wires up between a layout and a page for you, and there is no official API for a page to update the layout that wraps it. The only documented ways to keep a layout and a page in sync are reading the same URL data independently on both sides, sharing a cache-wrapped data function, or moving state into a client component that both can import.

For the full picture of what a layout can render and where it sits in the folder structure, see Layouts in Next.js: Root Layouts and Nested Layouts Explained. To read params and the query string in more depth, see Next.js params vs searchParams: How to Read URL Parameters.

Rune AI

Rune AI

Key Insights

  • Layouts cannot pass data to children, and pages cannot pass data up to a layout.
  • Both a layout and a page can read the same route params independently.
  • Wrap a shared data function in React's cache so a layout and a page reuse one result.
  • fetch calls are deduped automatically when a layout and a page request the same URL.
  • A layout never receives searchParams because it does not rerender on navigation.
RunePowered by Rune AI

Frequently Asked Questions

Can a page send data to the layout that wraps it?

No. There is no prop or channel for a page to pass data up to its layout. Only children flows from a layout down into a page.

Why does the same fetch call in a layout and a page not cost two requests?

Next.js automatically dedupes identical fetch calls made during the same render, and React's cache function does the same for other data sources such as a database client.

Can a layout read searchParams?

No. A layout does not rerender on navigation, so it never receives searchParams. Only a page or a client component can read the current query string.

Conclusion

A layout and the page it wraps cannot pass data to each other directly. Route params reach both independently, a shared fetch or a function wrapped in React's cache lets both sides use the same data without a second request, and anything that must react to a page's own state belongs in a client component instead.