Introducción/Guías/ISR

Cómo implementar Regeneración Estática Incremental (ISR)

Ejemplos

La Regeneración Estática Incremental (ISR) permite:

  • Actualizar contenido estático sin reconstruir todo el sitio
  • Reducir la carga del servidor sirviendo páginas estáticas prerrenderizadas para la mayoría de solicitudes
  • Asegurar que los encabezados cache-control adecuados se añadan automáticamente a las páginas
  • Manejar grandes cantidades de páginas de contenido sin tiempos largos de next build

Aquí un ejemplo mínimo:

import type { GetStaticPaths, GetStaticProps } from 'next'

interface Post {
  id: string
  title: string
  content: string
}

interface Props {
  post: Post
}

export const getStaticPaths: GetStaticPaths = async () => {
  const posts = await fetch('https://api.vercel.app/blog').then((res) =>
    res.json()
  )
  const paths = posts.map((post: Post) => ({
    params: { id: String(post.id) },
  }))

  // Prerrenderizaremos solo estas rutas en tiempo de compilación.
  // { fallback: 'blocking' } renderizará páginas en el servidor
  // bajo demanda si la ruta no existe.
  return { paths, fallback: false }
}

export const getStaticProps: GetStaticProps<Props> = async ({
  params,
}: {
  params: { id: string }
}) => {
  const post = await fetch(`https://api.vercel.app/blog/${params.id}`).then(
    (res) => res.json()
  )

  return {
    props: { post },
    // Next.js invalidará la caché cuando llegue una
    // solicitud, como máximo una vez cada 60 segundos.
    revalidate: 60,
  }
}

export default function Page({ post }: Props) {
  return (
    <main>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </main>
  )
}

Así funciona este ejemplo:

  1. Durante next build, se generan todas las entradas de blog conocidas (hay 25 en este ejemplo)
  2. Todas las solicitudes a estas páginas (ej. /blog/1) se almacenan en caché y son instantáneas
  3. Después de 60 segundos, la siguiente solicitud mostrará la página en caché (obsoleta)
  4. La caché se invalida y comienza a generarse una nueva versión de la página en segundo plano
  5. Una vez generada con éxito, Next.js mostrará y almacenará en caché la página actualizada
  6. Si se solicita /blog/26, Next.js generará y almacenará esta página bajo demanda

Referencia

Funciones

Ejemplos

Validación bajo demanda con res.revalidate()

Para un método más preciso de revalidación, use res.revalidate para generar una nueva página bajo demanda desde un Enrutador API.

Por ejemplo, esta Ruta API puede llamarse en /api/revalidate?secret=<token> para revalidar una entrada de blog. Cree un token secreto solo conocido por su app Next.js. Este secreto evitará acceso no autorizado a la Ruta API de revalidación.

import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  // Verificar secreto para confirmar solicitud válida
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Token inválido' })
  }

  try {
    // Esta debe ser la ruta real no reescrita
    // ej. para "/posts/[id]" debe ser "/posts/1"
    await res.revalidate('/posts/1')
    return res.json({ revalidated: true })
  } catch (err) {
    // Si hay error, Next.js continuará mostrando
    // la última página generada exitosamente
    return res.status(500).send('Error al revalidar')
  }
}

Si usa revalidación bajo demanda, no necesita especificar un tiempo revalidate en getStaticProps. Next.js usará el valor por defecto false (sin revalidación) y solo revalidará la página bajo demanda cuando se llame a res.revalidate().

Manejo de excepciones no capturadas

Si hay un error dentro de getStaticProps durante regeneración en segundo plano, o lanza un error manualmente, se seguirá mostrando la última página generada exitosamente. En la siguiente solicitud, Next.js reintentará llamar a getStaticProps.

import type { GetStaticProps } from 'next'

interface Post {
  id: string
  title: string
  content: string
}

interface Props {
  post: Post
}

export const getStaticProps: GetStaticProps<Props> = async ({
  params,
}: {
  params: { id: string }
}) => {
  // Si esta solicitud lanza un error no capturado, Next.js no
  // invalidará la página actualmente mostrada y
  // reintentará getStaticProps en la próxima solicitud.
  const res = await fetch(`https://api.vercel.app/blog/${params.id}`)
  const post: Post = await res.json()

  if (!res.ok) {
    // Si hay error del servidor, puede lanzar un error
    // en lugar de retornar para que la caché no se actualice
    // hasta la próxima solicitud exitosa.
    throw new Error(`Error al obtener entradas, estado recibido ${res.status}`)
  }

  return {
    props: { post },
    // Next.js invalidará la caché cuando llegue una
    // solicitud, como máximo una vez cada 60 segundos.
    revalidate: 60,
  }
}

Personalizando la ubicación de la caché

Puede configurar la ubicación de la caché de Next.js si desea persistir páginas y datos en almacenamiento duradero, o compartir la caché entre múltiples contenedores o instancias de su aplicación. Más información.

Solución de problemas

Depuración de datos en caché en desarrollo local

Si usa la API fetch, puede añadir registro adicional para entender qué solicitudes están en caché o no. Más sobre la opción logging.

next.config.js
module.exports = {
  logging: {
    fetches: {
      fullUrl: true,
    },
  },
}

Verificar el comportamiento correcto en producción

Para verificar que sus páginas se almacenan en caché y se revalidan correctamente en producción, puede probar localmente ejecutando next build y luego next start para ejecutar el servidor de producción de Next.js.

Esto le permitirá probar el comportamiento de ISR (Regeneración Incremental Estática) como funcionaría en un entorno de producción. Para depuración adicional, agregue la siguiente variable de entorno a su archivo .env:

.env
NEXT_PRIVATE_DEBUG_CACHE=1

Esto hará que el servidor de Next.js registre en la consola los aciertos y fallos de la caché ISR. Puede inspeccionar la salida para ver qué páginas se generan durante next build, así como cómo se actualizan las páginas cuando se accede a las rutas bajo demanda.

Consideraciones

  • ISR solo es compatible cuando se utiliza el entorno de ejecución Node.js (predeterminado).
  • ISR no es compatible al crear una Exportación Estática.
  • El Middleware no se ejecutará para solicitudes ISR bajo demanda, lo que significa que cualquier reescritura de ruta o lógica en el Middleware no se aplicará. Asegúrese de revalidar la ruta exacta. Por ejemplo, /post/1 en lugar de una reescritura /post-1.

Compatibilidad con plataformas

Opción de despliegueCompatible
Servidor Node.js
Contenedor Docker
Exportación estáticaNo
AdaptadoresDepende de la plataforma

Aprenda cómo configurar ISR al alojar Next.js usted mismo.

Historial de versiones

VersiónCambios
v14.1.0El cacheHandler personalizado es estable.
v13.0.0Se introduce el App Router.
v12.2.0Pages Router: ISR bajo demanda es estable
v12.0.0Pages Router: Se añade ISR con detección de bots.
v9.5.0Pages Router: Se introduce ISR estable.