`root-params` in Next.js: Reading Root Layout Params in Multi-Tenant Apps

next/root-params lets any Server Component read a dynamic segment from above the root layout without passing it down as a prop through every level.

6 min read

Next.js root-params, imported from next/root-params, let a Server Component read a dynamic segment from above the root layout directly, instead of receiving it as a prop passed down from a parent. This solves a real pain point in multi-tenant or multi-language apps, where a value like a locale is needed in dozens of unrelated components. The module was introduced in Next.js 16.3, so it is not available on earlier 16.x releases.

App.tsxApp.tsx
// app/[lang]/layout.tsx
import { lang } from "next/root-params";
 
type Props = { children: React.ReactNode };
 
export default async function RootLayout({ children }: Props) {
  const locale = await lang();
  return <html lang={locale}><body>{children}</body></html>;
}

For a folder structure where the root layout lives inside app/[lang], importing lang gives every Server Component in the tree a direct way to read that value. The exported function name always matches the dynamic segment's folder name, and calling it returns a promise that resolves to a plain string for a normal segment.

What makes a segment a root parameter

Only dynamic segments that appear above the root layout qualify. A segment deeper in the tree, such as a blog post slug, is a regular route parameter and stays on the params prop instead. This distinction exists because everything above the root layout is shared by every route beneath it, which is what makes it safe to read from anywhere.

texttext
app/
  [lang]/
    layout.tsx       -> root layout, lang is a root parameter
    page.tsx
    blog/
      [slug]/
        page.tsx      -> slug is a regular route parameter

Using it outside a layout or page

Because the exports are plain module imports, they also work inside shared server utilities that have no direct access to route props at all.

typescripttypescript
// lib/get-translations.ts
import { lang } from "next/root-params";
 
export async function getTranslations() {
  const language = await lang();
  return import(`@/locales/${language}.json`);
}

Any Server Component that calls getTranslations gets the correct language for the current request, without that component ever receiving lang as a prop.

Constraints to know

ConstraintDetail
Component typeServer Components only
Not supported inClient Components, Server Actions, route handlers
Naming ruleThe segment name must be a valid JavaScript identifier

A kebab-case segment like [post-slug] cannot become a root parameter getter, because it is not a valid function name. Rename the folder to something like [postSlug] if you need to read it this way.

When to reach for it

Use root parameters for values every part of the app needs, such as a locale, a region, or a tenant identifier in a multi-tenant product. For a value only a handful of nested pages need, the regular params prop covered in page.js props, params, and search params is simpler and does not require restructuring the route around a shared root segment.

A root parameter also plays a different role than a folder used purely for organization. If a value never changes what data a page needs, a route group is usually the better fit, and the difference between the two is covered in route groups in Next.js.

Root parameters and multiple root layouts

An app can define more than one root layout by removing the shared top-level layout and adding one inside each top-level route group instead. When a project mixes multiple root layouts, a parameter that exists in one but not another still works, and its getter returns undefined for routes rendered under the layout that never defined it. This keeps a single set of shared utilities working correctly across every section of a multi-tenant app, even when only some sections are tenant-scoped.

Rune AI

Rune AI

Key Insights

  • next/root-params exposes root-level dynamic segments as importable async functions.
  • A root parameter is any dynamic segment that sits above the root layout.
  • It works in Server Components only, not Client Components, Server Actions, or route handlers.
  • Each export name matches its dynamic segment folder name exactly.
  • Cache Components requires generateStaticParams to supply at least one value per root parameter.
RunePowered by Rune AI

Frequently Asked Questions

Can I use next/root-params in a Client Component?

No. The import fails at build time inside a Client Component, a Server Action, or a route handler. It only works in Server Components.

What counts as a root parameter?

Only dynamic segments that sit above the root layout in the folder tree count as root parameters. A dynamic segment deeper in the route, like a blog post slug, is a regular route parameter read through the params prop instead.

Do I need generateStaticParams to use a root parameter?

Not by default. It becomes required once Cache Components is enabled, because every root parameter then needs at least one known value for the build to succeed.

Conclusion

next/root-params gives Server Components a direct way to read a dynamic segment from above the root layout, such as a locale or tenant id, without threading it through props on every page in between.