Almacenamiento en caché
Comprende las cuatro capas de almacenamiento en caché en Next.js: memoización de solicitudes, caché de datos, caché de ruta completa y caché del enrutador.
Busca en todas las páginas de la documentación
Comprende las cuatro capas de almacenamiento en caché en Next.js: memoización de solicitudes, caché de datos, caché de ruta completa y caché del enrutador.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tarjeta de receta de referencia rápida -- lista para copiar y pegar.
// Capa 1: Memoización de solicitudes (automática para fetch, manual para otros)
// La misma URL de fetch se deduplica dentro de un único paso de renderizado
const data = await fetch("https://api.example.com/user/1"); // llamada en 3 componentes, solo 1 solicitud
// Memoización manual para llamadas que no son de fetch
import { cache } from "react";
export const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } });
});
// Capa 2: Caché de datos (persiste entre solicitudes)
await fetch(url, { next: { revalidate: 3600 } }); // almacenado en caché por 1 hora
await fetch(url, { cache: "no-store" }); // omitir caché de datos
await fetch(url, { next: { tags: ["users"] } }); // etiquetar para invalidación
// Capa 3: Caché de ruta completa (páginas estáticas en tiempo de compilación)
// Automático para rutas sin datos dinámicos
// Capa 4: Caché del enrutador (lado del cliente, en memoria)
// Automático para prefetch de <Link> y navegación atrás/adelanteCuándo usarlo: necesitas entender por qué tus datos están obsoletos, por qué una página no se está actualizando o cómo optimizar el rendimiento aprovechando la capa de caché correcta.
// lib/data.ts -- demostrando todas las capas de almacenamiento en caché
import { cache } from "react";
import { db } from "@/lib/db";
// ---- Capa 1: Memoización de solicitudes ----
// Esta función puede ser llamada desde múltiples Server Components
// en el mismo paso de renderizado -- solo se ejecuta una consulta de BD
export const getCurrentUser = cache(async () => {
const session = await getSession();
if (!session) return null;
return db.user.findUnique({ where: { id: session.userId } });
});
// ---- Capa 2: Caché de datos ----
export async function getProducts() {
const res = await fetch("https://api.example.com/products", {
next: { revalidate: 600, tags: ["products"] },
});
return res.json() as Promise<Product[]>;
}
// Sin almacenamiento en caché -- siempre fresco
export async function getCartItems(userId: string) {
const res = await fetch(`https://api.example.com/cart/${userId}`, {
cache: "no-store",
});
return res.json() as Promise<CartItem[]>;
}// app/layout.tsx -- getCurrentUser llamada aquí...
import { getCurrentUser } from "@/lib/data";
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const user = await getCurrentUser(); // Solicitud 1 (llamada real a BD)
return (
<html lang="en">
<body>
<nav>
<span>{user?.name ?? "Guest"}</span>
</nav>
{children}
</body>
</html>
);
}// app/dashboard/page.tsx -- ...y también llamada aquí (deduplicada)
import { getCurrentUser } from "@/lib/data";
export default async function DashboardPage() {
const user = await getCurrentUser(); // Solicitud 2 (memoizada -- sin llamada a BD)
return <h1>Bienvenido de vuelta, {user?.name}</h1>;
}Lo que esto demuestra:
React.cache deduplicando una llamada a base de datos entre dos Server Components en el mismo renderizadonext.revalidate colocando los resultados de fetch en la Caché de datoscache: "no-store" omitiendo la Caché de datos para datos específicos del usuariogetCurrentUser() sin desencadenar dos consultasfetch con la misma URL y opciones, React devuelve el resultado memoizado. Para llamadas que no son de fetch (base de datos, ORM), envuelve la función con React.cache(). La memoización se borra después de que se completa el renderizado.next.revalidate para expiración basada en tiempo e next.tags para invalidación bajo demanda vía revalidateTag().cookies(), headers(), searchParams o cache: "no-store") están excluidas.<Link>, la página siguiente puede que ya esté en caché. El caché del enrutador tiene diferentes tiempos de vida: 30 segundos para páginas dinámicas, 5 minutos para páginas estáticas (estos son valores predeterminados y configurables en Next.js 15+).Optar por no usar almacenamiento en caché para una ruta:
// app/real-time/page.tsx
export const dynamic = "force-dynamic"; // omite Full Route Cache
export const fetchCache = "force-no-store"; // omite Data Cache para todos los fetchesUsando unstable_cache para datos que no son de fetch:
import { unstable_cache } from "next/cache";
const getCachedPosts = unstable_cache(
async () => db.post.findMany(),
["all-posts"], // partes de la clave de caché
{
tags: ["posts"],
revalidate: 3600,
}
);Controlando el comportamiento de Router Cache:
// next.config.ts
import type { NextConfig } from "next";
const config: NextConfig = {
experimental: {
staleTimes: {
dynamic: 0, // no cachear páginas dinámicas en el cliente
static: 300, // cachear páginas estáticas por 5 minutos
},
},
};
export default config;// React.cache preserva la firma de la función
import { cache } from "react";
const getUser = cache(
async (id: string): Promise<User | null> => {
return db.user.findUnique({ where: { id } });
}
);
// getUser: (id: string) => Promise<User | null>
// Tipos de configuración de segmento
export const dynamic: "auto" | "force-dynamic" | "force-static" | "error" = "auto";
export const revalidate: number | false = 60;
export const fetchCache: "auto" | "default-cache" | "only-cache" |
"force-cache" | "force-no-store" | "default-no-store" | "only-no-store" = "auto";Confundir memoización de solicitudes con Caché de datos -- La memoización de solicitudes es por renderizado y efímera; la Caché de datos persiste entre solicitudes. Solución: usa React.cache() para deduplicación por solicitud y next.revalidate / next.tags para almacenamiento en caché persistente.
Caché del enrutador sirviendo páginas antiguas -- Después de una mutación, el Caché del enrutador lado del cliente puede seguir sirviendo la página anterior durante navegación atrás/adelante. Solución: llama a router.refresh() en el Client Component después de una Server Action, o configura staleTimes para reducir la duración del caché lado del cliente.
cache: "force-cache" no siempre es el valor predeterminado -- En Next.js 15+, el valor predeterminado es cache: "auto", que puede variar según el contexto (funciones dinámicas, configuración de ruta). Solución: sé explícito sobre el comportamiento de almacenamiento en caché estableciendo cache o next.revalidate en cada fetch.
Colisiones de clave unstable_cache -- Si dos llamadas a unstable_cache comparten las mismas partes de clave pero devuelven diferentes formas de datos, obtienes caché corrupto. Solución: usa matrices de clave únicas y descriptivas.
Middleware y Edge Runtime no comparten cachés -- La Caché de datos es por región de despliegue. Middleware ejecutándose en el edge puede que no vea el mismo caché que una función de servidor Node.js. Solución: sé consciente de los límites de caché en despliegues multi-región.
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
React.cache() | Necesitas deduplicación por solicitud para llamadas que no son de fetch | Necesitas que los datos persistan entre solicitudes |
unstable_cache | Necesitas semántica de Caché de datos para llamadas de base de datos u ORM | Fetch simple con next.revalidate funciona |
| Redis o Memcached | Necesitas un caché compartido entre múltiples instancias de servidor | El caché integrado de Next.js es suficiente |
SWR stale-while-revalidate | Quieres almacenamiento en caché lado del cliente con revalidación automática | El almacenamiento en caché lado del servidor cubre tus necesidades |
cache: "no-store" en todas partes | Los datos deben ser siempre frescos (dashboards en tiempo real) | Puedes tolerar datos obsoletos para mejor rendimiento |
import { cache } from "react";
import { db } from "@/lib/db";
export const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } });
});React.cache() para deduplicación por solicitudcache: "auto", no force-cache como en Next.js 14cache o next.revalidate en cada fetchstaleTimes en next.config.tsexport const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";force-dynamic omite Full Route Cacheforce-no-store omite Data Cache para todos los fetches en la rutarouter.refresh() en el Client Component o reduce staleTimes en la configuraciónunstable_cacheimport { cache } from "react";
const getUser = cache(
async (id: string): Promise<User | null> => {
return db.user.findUnique({ where: { id } });
}
);
// getUser: (id: string) => Promise<User | null>React.cache() proporciona solo deduplicación por solicitud; los datos no persisten entre solicitudesunstable_cache proporciona semántica de Caché de datos (persiste entre solicitudes, soporta tags y revalidación)unstable_cache para llamadas de base de datos u ORM que necesiten almacenamiento en caché entre solicitudes// next.config.ts
const config: NextConfig = {
experimental: {
staleTimes: {
dynamic: 0, // no cachear páginas dinámicas en el cliente
static: 300, // cachear páginas estáticas por 5 minutos
},
},
};export const fetchCache:
| "auto"
| "default-cache"
| "only-cache"
| "force-cache"
| "force-no-store"
| "default-no-store"
| "only-no-store" = "auto";Revisado por Chris St. John·Última actualización: 7 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥