next-intl nextjs 16: Caché de componentes con root-params
Domina la integración de next-intl en nextjs 16 aprovechando next/root-params para habilitar la caché de componentes de forma segura sin prop-drilling de tu locale.

Muchos equipos de ingeniería tienen dificultades para equilibrar la eficiencia del renderizado en servidor con una internacionalización robusta. Al actualizar a versiones modernas de Next.js, los desarrolladores suelen descubrir que la resolución de locale ligada a la request puede entrar en conflicto con el renderizado estático y los scopes cacheados de Server Components.
Esta guía explica cómo configurar next-intl con Next.js 16 Cache Components usando next/root-params, para que los Server Components anidados puedan resolver el locale activo sin pasarlo por cada layout, page y component.
next/root-params: Las versiones recientes de Next.js exponen segmentos de ruta raíz como[locale]mediante funciones getter async comolocale(), para que los Server Components puedan leer el locale activo sin prop-drilling.cacheComponents: Habilita Next.js Cache Components y la directiva de Reactuse cache.proxy.ts: En Next.js 16,middleware.tsestá deprecated y fue renombrado aproxy.ts.
También conviene saber:
requestLocale: En next-intl v4,getRequestConfigreciberequestLocale, que debería esperarse conawait, y la configuración devuelta debería incluirlocale.- Sin prop-drilling: Los Server Components anidados pueden resolver el locale directamente en lugar de recibirlo desde layouts padre.
- Límites actuales:
next/root-paramsestá pensado para Server Components. Los Client Components no pueden importarlo ni llamarlo directamente; pasa el locale como prop, o usa APIs de routing del lado del cliente cuando sea necesario.
¿Qué es el caching de next-intl en Next.js 16?
En esta configuración, el caching de next-intl significa usar Server Components localizados junto con la directiva de React use cache, mientras se resuelve el locale activo mediante next/root-params en lugar de headers de request.
Tradicionalmente, las bibliotecas de internacionalización solían depender de la request entrante para determinar el idioma activo. Podían leer el header Accept-Language, cookies u otros datos de la request, y luego pasar el locale a través de la app.
Eso funciona para renderizado dinámico, pero se vuelve problemático cuando quieres cachear o prerenderizar partes de la UI. Los scopes cacheados de Server Components deberían evitar APIs no cacheadas ligadas a la request, como headers() y cookies().
Next.js Cache Components hace que este límite sea más explícito. Si un componente está cacheado, debería depender de inputs seguros para la caché. Para rutas localizadas, el segmento de URL en sí es una mejor clave de caché que los headers de request.
El problema: caching y resolución de locale
Antes de next/root-params, los desarrolladores que usaban next-intl con renderizado estático solían depender de setRequestLocale(locale) para hacer que el locale estuviera disponible sin forzar renderizado dinámico.
Ese enfoque funciona, pero añade boilerplate. La función debe llamarse en cada layout y page que deba renderizarse estáticamente, porque Next.js puede renderizar layouts y pages de forma independiente.
next/root-params ofrece un camino más limpio. Permite que los Server Components lean root route params como [locale] directamente, sin pasar el locale mediante props.
next/root-params expone getters async generados para root params, como locale() o lang().
| Enfoque de arquitectura | Resolución de locale | ¿Compatible con use cache? |
Boilerplate |
|---|---|---|---|
| Renderizado ligado a la request | headers() / cookies() |
Encaja mal dentro de scopes cacheados | Bajo |
| Forzado estático | setRequestLocale(locale) |
Sí | Alto |
| Patrón de root params | next/root-params |
Sí, para Server Components | Bajo |
Versiones y limitaciones actuales
Usa este patrón solo cuando tus versiones instaladas soporten las APIs siguientes:
- Next.js 16 con
cacheComponents - Una versión de Next.js que incluya
next/root-params - Una versión reciente de next-intl v4
- React 19
next/root-params pasó por etapas experimentales y documentadas durante la línea de releases de Next.js 16. Verifica que tu versión instalada de Next.js exponga next/root-params antes de reemplazar setRequestLocale() en producción.
next/root-params es el sucesor de la API anterior unstable_rootParams. Permite generar funciones getter async a partir de root route params como locale() o lang().
Limitaciones actuales:
- Los Client Components no pueden importar ni llamar
next/root-paramsdirectamente. - Server Actions no están soportadas.
- Route Handlers no están soportados.
next/root-paramsestá pensado para Server Components.- Si necesitas el locale en un Client Component, pásalo desde un Server Component o lee route params con APIs de routing del lado del cliente como
useParams. - Prueba siempre tus versiones exactas de Next.js y next-intl antes de lanzar este patrón a producción.
Habilitar Cache Components y root params
Habilita Cache Components y root params en next.config.ts.
// next.config.ts
import createNextIntlPlugin from 'next-intl/plugin';
import type { NextConfig } from 'next';
const withNextIntl = createNextIntlPlugin();
const nextConfig: NextConfig = {
cacheComponents: true,
experimental: {
rootParams: true,
},
};
export default withNextIntl(nextConfig);
cacheComponents es una opción de nivel superior. En Next.js 16, controla el modelo de programación de Cache Components y unifica la configuración anterior de ppr, useCache y dynamicIO.
rootParams puede habilitarse explícitamente bajo experimental, mientras que cacheComponents habilita el modelo de caching que hace útil este patrón.
Estructura de app requerida
Para que next/root-params exponga [locale], el segmento de locale debe formar parte del árbol del root layout. Eso significa que tu root layout debería vivir dentro de app/[locale]/layout.tsx.
Estructura recomendada:
src/
├── i18n/
│ ├── routing.ts
│ └── request.ts
├── proxy.ts
└── app/
└── [locale]/
├── layout.tsx
└── page.tsx
Para este patrón, evita colocar un root app/layout.tsx por encima de [locale], porque [locale] debe formar parte del árbol del root layout para exponerse mediante next/root-params.
Los parámetros de ruta más profundos en el árbol se siguen accediendo mediante la prop params. Por ejemplo, en app/[locale]/blog/[slug]/page.tsx, locale puede ser un root param, mientras que slug sigue siendo un route param normal.
Configurar proxy.ts
En Next.js 16, middleware.ts está deprecated y fue renombrado a proxy.ts. La función exportada debería llamarse proxy, o puedes usar la forma soportada de default export.
// src/proxy.ts
import createMiddleware from 'next-intl/middleware';
import { routing } from './i18n/routing';
export const proxy = createMiddleware(routing);
export const config = {
matcher: '/((?!api|trpc|_next|_vercel|.*\\..*).*)',
};
El matcher excluye rutas internas comunes, API routes, internos de Vercel y archivos con extensiones como favicon.ico.
Advertencia sobre runtime
proxy.ts usa el runtime de Node.js. La opción de configuración runtime no está disponible en archivos Proxy.
Si necesitas específicamente comportamiento de Edge runtime, middleware.ts todavía funciona en Next.js 16, pero está deprecated. Se espera que sea eliminado en una versión futura.
Configurar el request config de next-intl
En next-intl v4, getRequestConfig recibe requestLocale cuando usas routing basado en locale. Deberías esperarlo con await y devolver el locale final.
También puedes recurrir a next/root-params cuando requestLocale no esté disponible en scopes cacheados de Server Components.
// src/i18n/request.ts
import { locale as getRootLocale } from 'next/root-params';
import { hasLocale } from 'next-intl';
import { getRequestConfig } from 'next-intl/server';
import { notFound } from 'next/navigation';
import { routing } from './routing';
export default getRequestConfig(async ({ requestLocale }) => {
let locale = await requestLocale;
if (!locale) {
const paramValue = await getRootLocale();
if (hasLocale(routing.locales, paramValue)) {
locale = paramValue;
} else {
notFound();
}
}
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
};
});
Esto elimina la necesidad de llamar setRequestLocale(locale) en cada layout y page para este caso de uso centrado en caching.
Fuera de esta configuración, setRequestLocale() sigue siendo el enfoque documentado de next-intl para habilitar renderizado estático.
Simplificar el localized root layout
Ahora tu localized root layout puede leer el locale activo directamente desde next/root-params.
// src/app/[locale]/layout.tsx
import { locale as getRootLocale } from 'next/root-params';
import { hasLocale } from 'next-intl';
import { notFound } from 'next/navigation';
import type { ReactNode } from 'react';
import { routing } from '@/i18n/routing';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}
type LocaleLayoutProps = {
children: ReactNode;
};
export default async function LocaleLayout({ children }: LocaleLayoutProps) {
const locale = await getRootLocale();
if (!hasLocale(routing.locales, locale)) {
notFound();
}
return (
<html lang={locale}>
<body>{children}</body>
</html>
);
}
generateStaticParams() sigue siendo importante para prerenderizar rutas localizadas. Con Cache Components habilitado, los root parameters necesitan valores estáticos para shells prerenderizables.
Usar use cache con componentes localizados
Una vez que el locale está disponible mediante next/root-params, los Server Components cacheados pueden usarlo como parte de su input seguro para la caché.
// src/app/[locale]/pricing/PricingSection.tsx
import { locale as getRootLocale } from 'next/root-params';
import { getTranslations } from 'next-intl/server';
async function fetchPricingTiers(locale: string) {
return [
{ id: '1', title: locale === 'de' ? 'Basis' : 'Basic' },
{ id: '2', title: locale === 'de' ? 'Profi' : 'Pro' },
];
}
export default async function PricingSection() {
'use cache';
const locale = await getRootLocale();
const t = await getTranslations('PricingSection');
const tiers = await fetchPricingTiers(locale);
return (
<section className="rounded-xl border border-neutral-200 p-6">
<h2 className="text-xl font-bold">{t('heading')}</h2>
<ul className="mt-4 space-y-2">
{tiers.map((tier) => (
<li key={tier.id} className="text-neutral-600">
{tier.title}
</li>
))}
</ul>
</section>
);
}
Esto permite que componentes profundamente anidados obtengan traducciones y datos localizados sin recibir locale como prop desde la page o el layout.
Next.js puede rastrear qué root parameter getters usa una función cacheada. Eso significa que el output cacheado puede separarse por el root parameter relevante, como locale, en lugar de depender de headers de request.
Verificar el build de producción
Ejecuta un build de producción:
npm run build
Las rutas que sean completamente prerenderizables deberían aparecer como estáticas o prerenderizadas en el output del build.
Si una ruta localizada se vuelve dinámica, inspecciona el render path para detectar:
headers()cookies()- acceso a datos no cacheado
- APIs ligadas a la request
generateStaticParams()faltante- lógica de ruta que impide el prerendering
Las funciones cacheadas no pueden acceder directamente a cookies(), headers() ni searchParams; léelos fuera del scope cacheado y pásalos como argumentos.
No todas las rutas localizadas deben ser estáticas. El objetivo es hacer posibles rutas estáticas y cacheadas sin hacer prop-drilling del locale.
Errores comunes
1. Mantener app/layout.tsx por encima de [locale]
Si [locale] no forma parte del árbol del root layout, next/root-params no puede exponerlo como root param.
Mueve el root layout a:
app/[locale]/layout.tsx
2. Tratar searchParams como una función
En las pages modernas de Next.js App Router, searchParams es una prop Promise. Espérala directamente con await.
Correcto:
const params = await searchParams;
Incorrecto:
const params = await searchParams();
Para Client Components, usa la función use() de React para leer la Promise en lugar de hacer que el componente sea async.
3. Usar convenciones antiguas de middleware
middleware.ts todavía se ejecuta en Next.js 16, pero está deprecated.
Usa:
proxy.ts
Y exporta una función default o una función nombrada proxy:
export const proxy = createMiddleware(routing);
4. Usar versiones desactualizadas de next-intl
Usa una versión reciente de next-intl v4. next-intl v3 no proporciona el mismo comportamiento de request config necesario para este patrón.
Antes de publicar un pin exacto de paquete, verifica la versión actual del paquete con tu package manager.
5. Esperar soporte directo en Client Components, Server Action o Route Handler
next/root-params es para Server Components. Los Client Components no pueden importarlo ni llamarlo directamente, y actualmente no soporta Server Actions ni Route Handlers.
Si necesitas el locale en un Client Component, pásalo desde un Server Component o usa APIs de routing del lado del cliente como useParams.
Si necesitas el locale en una Server Action, pásalo explícitamente como argumento desde el componente que llama la action.
FAQ
¿Cómo uso use cache con next-intl?
Habilita cacheComponents: true en next.config.ts.
Si tu versión de Next.js incluye next/root-params, habilita también root params y configura getRequestConfig para resolver el locale desde requestLocale, con next/root-params como fallback cuando sea necesario.
// next.config.ts
const nextConfig = {
cacheComponents: true,
experimental: {
rootParams: true,
},
};
¿Por qué el manejo de locale puede romper el renderizado estático?
El manejo de locale puede romper el renderizado estático cuando depende de APIs ligadas a la request como headers() o cookies(). Esas APIs hacen que el renderizado sea específico de la request, lo que entra en conflicto con el renderizado estático y los scopes cacheados de Server Components.
¿Qué es next/root-params?
next/root-params es una API de servidor de Next.js que expone root route params como funciones getter async.
Por ejemplo, si tu segmento dinámico raíz es [locale], puedes usar:
import { locale } from 'next/root-params';
const value = await locale();
Si tu segmento es [lang], el getter generado es lang().
Los nombres de root parameters deben ser identificadores válidos de funciones JavaScript, así que evita nombres como [post-slug] para root params a los que quieras acceder de esta manera.
¿Sigo necesitando setRequestLocale?
Para este patrón con next/root-params y Cache Components, por lo general no necesitas llamar setRequestLocale() en cada page y layout.
Fuera de esta configuración, o en versiones de Next.js donde next/root-params no esté disponible, setRequestLocale() sigue siendo el enfoque documentado de next-intl para habilitar renderizado estático.
¿Puedo usar next/root-params dentro de unstable_cache?
No. Usa la directiva de React use cache con Cache Components en su lugar.
next/root-params está diseñado para funcionar con use cache, donde Next.js puede rastrear los root parameter getters usados por la función cacheada.
Conclusión
Next.js 16 Cache Components hace que los límites de renderizado sean más explícitos, y las apps internacionalizadas necesitan resolución de locale que funcione dentro de esos límites.
Al combinar cacheComponents, next/root-params y la configuración de request de next-intl v4, puedes eliminar el prop-drilling repetitivo de locale, evitar la resolución de locale basada en request headers en Server Components cacheados y mantener las rutas localizadas elegibles para prerendering.
Si estás construyendo dashboards SaaS multilingües, admin panels o productos de plantillas, este patrón te da una base más limpia para Server Components localizados en Next.js 16.
Construye más rápido con Aniq UI
Las plantillas de Aniq UI te dan bases de Next.js listas para producción con TypeScript, Tailwind CSS, App Router layouts, Server Components, animaciones y patrones modernos de React.
Si estás construyendo un dashboard SaaS, landing page o admin panel, empezar desde una plantilla pulida puede ahorrar tiempo de configuración en routing, layouts, estados de UI y patrones de renderizado.
Referencias
- Docs de Next.js Proxy
- Guía de actualización a Next.js 16
- Docs de Next.js Cache Components
- Docs de Next.js
use cache - Docs de la convención de archivo
page.jsde Next.js - Docs de Next.js
useParams - Docs de configuración de routing de next-intl
- Docs de configuración de request de next-intl
- Discusión de root params en next-intl
- Docs de Next.js
next/root-paramsen el repo de Vercel


