Estrategias de caché con Claude Code para aplicaciones reales
Guía práctica para diseñar caché HTTP, CDN, Service Worker, Redis e invalidación con Claude Code.
El caché no es un interruptor mágico para acelerar una aplicación. En un producto real, los encabezados HTTP, el CDN, un Service Worker, Redis y la memoria del proceso guardan datos distintos durante tiempos distintos. Si le pides a Claude Code “añade caché” sin reglas, puede hacer que la app parezca más rápida, pero también puede mostrar precios viejos, inventario desactualizado o información privada a la persona equivocada.
Esta guía resume una estrategia que puedes entregar a Claude Code antes de que modifique código. Masa la probó en una pequeña app Express y en un flujo de sitio de contenidos; la mejora más clara vino de decidir qué capa era dueña de cada dato antes de añadir Redis o Service Worker.
flowchart LR
User[Browser] --> Http[HTTP cache]
Http --> SW[Service worker Cache API]
SW --> CDN[CDN or edge cache]
CDN --> App[Node or app server]
App --> Redis[Redis or app cache]
App --> DB[(Database)]
Empieza por las decisiones
Antes de que Claude Code implemente nada, responde cuatro preguntas:
- Qué usuarios pueden ver la misma respuesta.
- Cuánto puede envejecer el dato sin causar daño.
- Qué key, URL o etiqueta se elimina después de una actualización.
- Quién ejecuta el rollback o purge cuando el caché está mal.
Imágenes, CSS y bundles JavaScript con hash pueden vivir mucho tiempo. Páginas de facturación, ajustes de cuenta y HTML autenticado no deben entrar en un caché compartido. La guía de MDN sobre HTTP caching explica la diferencia entre cachés privados del navegador y cachés compartidos como proxies o CDN.
Comparación de capas
| Capa | Mejor uso | TTL orientativo | Invalidación | Error frecuente |
|---|---|---|---|---|
| Caché HTTP del navegador | Imágenes, CSS, JS, API pública corta | 1 minuto a 1 año | Cambio de nombre, ETag, Cache-Control | API demasiado cacheada muestra pantallas viejas |
| CDN o edge | Listas de productos, HTML de artículos, OGP | 30 segundos a 1 día | Purge por URL, etiqueta o despliegue | HTML autenticado queda público |
| Service Worker Cache API | Página offline, app shell, JSON poco cambiante | Por versión | Cambiar nombre de caché en release | Worker viejo sirve bundles viejos |
| Redis o caché de app | Agregados DB, API externas, rankings | 10 segundos a 1 hora | Diseño de keys, eventos, TTL | KEYS bloquea Redis en producción |
| Memoria de proceso | Configuración, feature flags cortos | Segundos a minutos | Reinicio o clear explícito | Instancias con valores distintos |
Incluye esta tabla en CLAUDE.md para que Claude Code tenga reglas estables al crear rutas nuevas. Para instrucciones de proyecto, consulta CLAUDE.md best practices.
Caso 1: encabezados HTTP en Express
El primer caché que conviene arreglar suele ser el encabezado de respuesta, no Redis. Cache-Control indica a navegadores y CDN cuánto tiempo pueden almacenar una respuesta. MDN documenta los detalles en Cache-Control header.
Copia esto como server.js y ejecútalo.
npm install express
node server.js
// server.js
const express = require("express");
const app = express();
function cacheControl(req, res, next) {
const path = req.path;
if (path.startsWith("/assets/")) {
res.set("Cache-Control", "public, max-age=31536000, immutable");
return next();
}
if (path.startsWith("/api/private/")) {
res.set("Cache-Control", "no-store");
return next();
}
if (path.startsWith("/api/public/")) {
res.set("Cache-Control", "public, max-age=60, s-maxage=300, stale-while-revalidate=600");
res.set("Vary", "Accept-Encoding");
return next();
}
res.set("Cache-Control", "no-cache");
next();
}
app.use(cacheControl);
app.use("/assets", express.static("public/assets"));
app.get("/api/public/products", (_req, res) => {
res.json({ items: ["book", "template", "consultation"], generatedAt: new Date().toISOString() });
});
app.get("/api/private/me", (_req, res) => {
res.json({ userId: "demo-user", plan: "team" });
});
app.listen(3000, () => {
console.log("http://localhost:3000");
});
La decisión importante es separar rutas públicas y privadas. /api/private/ usa no-store, por lo que ni el navegador ni el CDN deberían guardar la respuesta. Las API públicas usan un TTL corto para navegador y uno algo más largo para CDN con s-maxage.
Al pedirlo a Claude Code, escribe la regla: las respuestas autenticadas deben usar no-store; solo las rutas públicas pueden usar s-maxage.
Caso 2: helper getOrSet con Redis
Redis sirve para reducir consultas repetidas a la base de datos o a API externas. El patrón seguro por defecto es cache-aside: mirar Redis, cargar desde la fuente si no existe, y guardar el valor con TTL.
npm install redis
// cache.js
const { createClient } = require("redis");
const redis = createClient({
url: process.env.REDIS_URL || "redis://localhost:6379",
});
let connecting;
async function client() {
if (redis.isOpen) return redis;
if (!connecting) connecting = redis.connect();
await connecting;
return redis;
}
async function getOrSet(key, ttlSeconds, loader) {
const r = await client();
const cached = await r.get(key);
if (cached !== null) {
return JSON.parse(cached);
}
const fresh = await loader();
await r.set(key, JSON.stringify(fresh), { EX: ttlSeconds });
return fresh;
}
async function invalidate(keys) {
const r = await client();
if (keys.length > 0) {
await r.del(keys);
}
}
module.exports = { getOrSet, invalidate };
// products.js
const { getOrSet, invalidate } = require("./cache");
async function loadProductsFromDb() {
return [
{ id: "p1", name: "Prompt Templates", price: 500 },
{ id: "p2", name: "Claude Code Consultation", price: 15000 },
];
}
async function getPublicProducts() {
return getOrSet("products:list:v1", 300, loadProductsFromDb);
}
async function updateProduct(productId, patch) {
console.log("update db", productId, patch);
await invalidate(["products:list:v1", `products:item:${productId}:v1`]);
}
module.exports = { getPublicProducts, updateProduct };
Evita KEYS products:* en producción. A medida que crece el keyspace, puede bloquear Redis. Usa listas de keys conocidas, sets de keys relacionadas o un comando de mantenimiento basado en SCAN.
Caso 3: versionado con Service Worker Cache API
Un Service Worker puede interceptar peticiones del navegador. La Cache API permite guardar página offline, app shell y assets estáticos. El riesgo es servir código viejo: si el nombre del caché no cambia, un worker antiguo puede seguir entregando JavaScript viejo después de desplegar.
// public/sw.js
const CACHE_VERSION = "claude-code-cache-v2026-06-01";
const STATIC_CACHE = `${CACHE_VERSION}:static`;
const PRECACHE_URLS = ["/", "/offline.html", "/assets/app.css"];
self.addEventListener("install", (event) => {
event.waitUntil(
caches
.open(STATIC_CACHE)
.then((cache) => cache.addAll(PRECACHE_URLS))
.then(() => self.skipWaiting())
);
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches
.keys()
.then((names) =>
Promise.all(
names
.filter((name) => !name.startsWith(CACHE_VERSION))
.map((name) => caches.delete(name))
)
)
.then(() => self.clients.claim())
);
});
self.addEventListener("fetch", (event) => {
const request = event.request;
if (request.method !== "GET") return;
event.respondWith(
caches.match(request).then((cached) => {
if (cached) return cached;
return fetch(request)
.then((response) => {
if (response.ok && new URL(request.url).pathname.startsWith("/assets/")) {
const copy = response.clone();
caches.open(STATIC_CACHE).then((cache) => cache.put(request, copy));
}
return response;
})
.catch(() => caches.match("/offline.html"));
})
);
});
Regístralo desde la entrada del cliente.
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/sw.js");
});
}
Indica a Claude Code que el nombre del caché debe incluir fecha de release o build ID, y que los cachés antiguos se eliminan en activate.
Caso 4: prompt de auditoría para Claude Code
Claude Code aporta más valor cuando audita todo el repositorio, no cuando solo añade un helper. Los Claude Code common workflows recomiendan ciclos pequeños de investigación, edición y verificación; el trabajo de caché encaja bien ahí.
Eres responsable de auditar el comportamiento de caché en una aplicación web.
Inspecciona este repositorio buscando encabezados HTTP, supuestos de CDN, Service Worker, Redis y cachés en memoria de proceso.
Devuelve:
1. Datos guardados por cada capa
2. TTL y condición de invalidación
3. Riesgo de que datos personales o autenticados lleguen a caché compartido
4. Pantallas concretas donde puede aparecer stale data
5. Plan mínimo de corrección y comandos de verificación
Restricciones:
- Marca claramente las suposiciones
- Sigue los patrones existentes del proyecto
- Propón refactors grandes por separado, sin aplicarlos de inmediato
Este prompt funciona como caché de contexto reutilizable. En vez de explicar la política cada vez, guárdala en una plantilla o en CLAUDE.md y añade solo el diff actual.
Escenarios prácticos
En un catálogo de productos o tienda de plantillas, las tarjetas públicas pueden vivir poco tiempo en CDN y la lista de base de datos puede vivir cinco minutos en Redis. Al editar un producto, elimina la key de lista y purga la URL afectada en el CDN.
En un dashboard administrativo, ingresos, páginas vistas y conversiones pueden cachearse entre 30 segundos y 5 minutos. Permisos, notificaciones personales y facturación deben ser private o no-store.
En documentación y blogs, el HTML de artículos puede vivir poco tiempo en edge, los assets con hash pueden ser de larga duración y la shell offline puede depender del Service Worker. Es un patrón adecuado para sitios con mucho contenido como ClaudeCodeLab.
En API externas, Redis ayuda a absorber límites de uso para datos como clima, divisas, planes SaaS o feeds de estado. Pide a Claude Code revisar los términos oficiales, porque algunos proveedores limitan el almacenamiento.
Trampas comunes
El error más grave es cachear HTML autenticado en un CDN. Si la respuesta depende de cookies, usa private o no-store por defecto. Si necesitas velocidad de CDN, separa la shell pública de los datos específicos del usuario.
La falta de Vary también causa respuestas incorrectas. Si idioma, compresión, dispositivo o autorización cambian la respuesta, separa la URL o envía el Vary correcto.
Redis puede sufrir cache stampede cuando una key popular expira y muchas peticiones golpean la base de datos al mismo tiempo. Añade jitter al TTL, un lock corto o un fallback tipo stale-while-revalidate.
Service Worker puede mantener vivos archivos eliminados. Versiona el caché, borra nombres antiguos en activate y conserva un procedimiento de emergencia para desregistrar el worker.
Runbook de invalidación
- Define el alcance: producto, artículo, usuario o toda la app.
- Completa primero la escritura en DB; si falla, no borres caché.
- Elimina Redis con keys conocidas, sets relacionados o
SCAN. - Purga CDN por URL o etiqueta. Purga total solo como último recurso.
- Sube la versión del caché del Service Worker y confirma que desaparecen los antiguos.
- Verifica con
curl -I, DevTools y logs de hit rate de Redis. - En incidente, acorta TTL o mueve rutas sensibles a
no-store, y luego vuelve gradualmente.
Incluye este runbook en la definición de terminado de Claude Code. Para disciplina de flujo, combínalo con Claude Code productivity tips.
Formación, plantillas y consulta
Si quieres convertir esto en un flujo repetible para tu equipo, empieza por la biblioteca de productos y plantillas de ClaudeCodeLab para unificar CLAUDE.md, prompts de review y prompts de auditoría. Si el reto es mapear CDN, Redis, permisos y revisión sobre un repositorio real, usa la página de formación y consulta de Claude Code.
Como referencias oficiales, revisa MDN sobre HTTP caching, la Cache API, Cache-Control y los Claude Code common workflows.
Después de probar los ejemplos de este artículo, Masa vio menos solicitudes repetidas de assets estáticos, respuestas públicas más predecibles con TTL orientado a CDN y lecturas innecesarias de base de datos más visibles gracias a getOrSet. Service Worker dejó la lección principal: sin borrado versionado, CSS viejo puede sobrevivir al despliegue. La ganancia real no es solo velocidad; es escribir dónde puede envejecer cada valor.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Permission receipt para Claude Code: alcance, prueba y rollback
Patrón de permission receipt para Claude Code: acciones permitidas, aprobación, pruebas, rollback y CTA de ingresos.
Agent Harness seguro para Claude Code y Codex: permisos, verificacion y rollback
Diseña un Agent Harness seguro para Claude Code y Codex con permisos, plan, verificaciones y rollback.
Subagentes de Claude Code: guía práctica para delegar trabajo de forma segura
Guía práctica de subagentes en Claude Code para dividir artículos y código: reglas, prompts, riesgos y checklist.