Back

Caché Inteligente en Next.js: Renderizado Parcial y Componentes Reutilizables

Caché Inteligente en Next.js: Renderizado Parcial y Componentes Reutilizables

Has construido una aplicación con el App Router de Next.js. La obtención de datos funciona. Las páginas se renderizan. Pero no estás seguro de si tu estrategia de caché es correcta, o si siquiera tienes una. Has visto datos obsoletos aparecer inesperadamente, observado la misma consulta de base de datos ejecutarse múltiples veces por solicitud, y te has preguntado por qué algunas rutas se sienten lentas a pesar de ser “estáticas”.

Este artículo explica cómo funciona realmente el almacenamiento en caché de datos del App Router de Next.js, cómo interactúan las tres capas de caché, y cómo construir componentes de servidor reutilizables que encapsulen tanto la obtención de datos como la política de caché. También cubriremos el Partial Prerendering de Next.js y cómo el renderizado parcial de React 19 habilita estrategias de caché a nivel de componente.

Puntos Clave

  • Next.js utiliza tres capas de caché (Data Cache, Full Route Cache, Router Cache) que se combinan en cascada durante las solicitudes
  • Los componentes deben ser propietarios de su política de caché usando cache() de React para deduplicación y opciones de fetch para control de vida útil
  • La revalidación basada en etiquetas permite la invalidación quirúrgica de caché en múltiples rutas
  • Partial Prerendering (PPR) permite mezclar shells estáticos con contenido dinámico en streaming a través de límites de Suspense

Cómo Funcionan Juntas las Tres Capas de Caché

El almacenamiento en caché de Next.js opera a través de tres mecanismos distintos que interactúan durante cada solicitud.

Data Cache (Caché de Datos)

El Data Cache persiste los resultados de fetch entre solicitudes y despliegues. Cuando llamas a fetch con el almacenamiento en caché habilitado, Next.js almacena la respuesta del lado del servidor. Las solicitudes subsiguientes devuelven datos en caché hasta que ocurre la revalidación.

// Almacenado en caché por 1 hora en todas las solicitudes
const posts = await fetch('https://api.example.com/posts', {
  next: { revalidate: 3600 }
})

Full Route Cache (Caché de Ruta Completa)

En tiempo de compilación, Next.js renderiza rutas estáticas en HTML y payloads RSC. Este Full Route Cache sirve contenido prerenderizado instantáneamente. Las rutas puramente dinámicas omiten este caché, pero las rutas con segmentos estáticos o revalidación aún pueden generar shells estáticos.

Router Cache del Lado del Cliente

El navegador almacena payloads RSC en memoria durante la navegación. Los layouts persisten a través de cambios de ruta. Las rutas visitadas se almacenan en caché en memoria durante la sesión y se reutilizan durante la navegación hasta que se invalidan.

Estas capas se combinan en cascada: invalidar el Data Cache afecta las solicitudes subsiguientes, y el Full Route Cache o Router Cache se actualizan en el siguiente renderizado que requiera datos frescos.

Construyendo Componentes de Servidor Reutilizables con Caché

El modelo mental que previene errores de datos obsoletos: los componentes deben ser propietarios de su política de caché.

// lib/data.ts
import { cache } from 'react'

export const getProduct = cache(async (id: string) => {
  const res = await fetch(`https://api.example.com/products/${id}`, {
    next: { revalidate: 300, tags: ['products', `product-${id}`] }
  })
  return res.json()
})

Esta función puede ser llamada desde cualquier componente: layout, página o hijo anidado. El cache() de React deduplica llamadas dentro de un único pase de renderizado. La opción next.revalidate controla la vida útil del Data Cache. Las etiquetas permiten invalidación quirúrgica.

Usa esta función en cualquier lugar sin prop drilling:

// app/products/[id]/page.tsx
export default async function ProductPage({ params }: { params: { id: string } }) {
  const { id } = await params
  const product = await getProduct(id)
  return <ProductDetails product={product} />
}

Configurando el Comportamiento de Caché con Opciones de Segmento de Ruta

Más allá de las opciones de fetch, las configuraciones de segmento de ruta controlan el almacenamiento en caché a nivel de ruta:

// Forzar renderizado dinámico
export const dynamic = 'force-dynamic'

// Establecer período de revalidación para todos los fetches
export const revalidate = 3600

Para invalidación bajo demanda, usa revalidatePath o revalidación basada en etiquetas:

// app/actions.ts
'use server'
import { revalidateTag } from 'next/cache'

export async function updateProduct(id: string) {
  // await db.product.update(...)
  revalidateTag(`product-${id}`)
}

Partial Prerendering de Next.js: La Dirección Experimental

El Partial Prerendering de Next.js representa un cambio significativo. En lugar de elegir entre rutas completamente estáticas o completamente dinámicas, PPR prerenderiza un shell estático mientras transmite contenido dinámico a través de límites de Suspense.

import { Suspense } from 'react'

export default async function ProductPage({ params }: { params: { id: string } }) {
  const { id } = await params
  
  return (
    <>
      {/* Shell estático - prerenderizado */}
      <Header />
      <ProductInfo id={id} />
      
      {/* Hueco dinámico - se transmite en tiempo de solicitud */}
      <Suspense fallback={<CartSkeleton />}>
        <UserCart />
      </Suspense>
    </>
  )
}

Las porciones estáticas se sirven instantáneamente. Las secciones dinámicas se transmiten a medida que se resuelven. Esta característica aún es experimental—habilítala mediante ppr: true en las opciones experimentales de tu next.config.js—pero apunta hacia el futuro del almacenamiento en caché de Next.js.

React 19 y Caché a Nivel de Componente

El comportamiento mejorado de Suspense en React 19 habilita estrategias de caché más granulares. Los componentes envueltos en Suspense pueden gestionar independientemente su ciclo de vida de datos. Usando las APIs experimentales use cache y cacheLife, puedes almacenar en caché subárboles de componentes en lugar de páginas completas:

import { cacheLife } from 'next/cache'

async function BlogPosts() {
  'use cache'
  cacheLife('hours')
  
  const res = await fetch('https://api.example.com/posts')
  const posts = await res.json()
  return <PostList posts={posts} />
}

La revalidación basada en etiquetas permite a los equipos compartir datos en caché de forma segura entre rutas. Un componente de producto usado tanto en /products/[id] como en /checkout puede ser invalidado una vez, actualizándose en todas partes.

Conclusión

Construye componentes de servidor que encapsulen su política de caché. Usa cache() de React para deduplicación de solicitudes, opciones de fetch para control del Data Cache, y etiquetas para invalidación entre rutas. Partial Prerendering es experimental pero vale la pena entenderlo: es hacia donde se dirige el almacenamiento en caché de Next.js.

El objetivo no es el máximo almacenamiento en caché. Es un almacenamiento en caché predecible que coincida con los requisitos reales de frescura de tus datos.

Preguntas Frecuentes

El cache() de React deduplica llamadas de función dentro de un único pase de renderizado, evitando que los mismos datos sean obtenidos múltiples veces durante una solicitud. El almacenamiento en caché de fetch de Next.js persiste resultados a través de múltiples solicitudes y despliegues usando el Data Cache. Usa ambos juntos: cache() para deduplicación en tiempo de renderizado y opciones de fetch para persistencia entre solicitudes.

Usa revalidateTag cuando necesites invalidar datos específicos a través de múltiples rutas, como información de producto mostrada tanto en páginas de detalle como de checkout. Usa revalidatePath cuando quieras invalidar todos los datos en caché para una ruta URL específica. Las etiquetas ofrecen control más quirúrgico mientras que las rutas son más simples para invalidación de una sola ruta.

Verifica tu salida de compilación para indicadores de ruta. Las rutas estáticas muestran un ícono de círculo mientras que las rutas dinámicas muestran un símbolo lambda. También puedes agregar declaraciones console.log en tus componentes—si registran en cada solicitud, la ruta es dinámica. Usar cookies(), headers() o searchParams automáticamente opta las rutas por renderizado dinámico.

Partial Prerendering todavía es experimental a partir de Next.js 15. Aunque puedes habilitarlo para pruebas, aún no se recomienda para aplicaciones en producción. La API y el comportamiento pueden cambiar en futuras versiones. Monitorea la documentación de Next.js y las notas de lanzamiento para actualizaciones de estabilidad antes de adoptarlo en producción.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay