// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const secret = request.nextUrl.searchParams.get('secret');
const tag = request.nextUrl.searchParams.get('tag');
if (secret !== process.env.MY_WEBHOOK_SECRET) {
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
}
if (!tag) {
return NextResponse.json({ message: 'Missing tag' }, { status: 400 });
}
revalidateTag(tag);
return NextResponse.json({ revalidated: true, now: Date.now() });
}Salutare! Am văzut prea multe proiecte în App Router unde lumea trântește export const revalidate = 60 pe fiecare pagină, fără să se gândească la consecințe. Am trecut și eu prin asta acum doi ani la un e-commerce cu 45k de SKU-uri, unde am reușit performanța să blochez API-ul de la PIM din cauza revalidărilor inutile în fundal.
Hai să clarificăm scurt opțiunile și să vedem cum le alegem rațional, nu din burtă.
Strategiile pe înțelesul tuturor
- SSG (Static Site Generation): Paginile se generează o singură dată, la build. E varianta cea mai rapidă și mai ieftină de servit, dar conținutul e înghețat în timp până la următorul deploy.
- ISR (Incremental Static Regeneration cu timp): Pagina e statică, dar la fiecare $X$ secunde, prima cerere declanșează o regenerare silențioasă pe server. Până se termină regenerarea, userii primesc pagina veche (stale).
- On-Demand Revalidation: Pagina e statică, dar o invalidezi explicit prin
revalidatePath()saurevalidateTag()când se schimbă ceva în CMS sau DB (de obicei printr-un Webhook).
Diagrama decizională: 5 cazuri din viața reală
1. Pagina de Termeni și Condiții / Landing Page
Alegere: SSG pur (force-static).
Conținutul se schimbă o dată la 6 luni. N-are niciun sens să lași procesul de Node.js să verifice ceva în runtime. Dacă modifici ceva, dai un push în Git sau dai trigger la un build nou. Simplu, ieftin, imposibil de spart.
2. Blog tehnic sau Documentație
Alegere: On-Demand Revalidation pe bază de tag (revalidateTag('posts')).
Când editezi un articol în Strapi sau Sanity, trimiți un webhook către Next.js și invalidezi doar acel articol și lista de postări. La un proiect de docs cu 3.000 de pagini, am scăzut timpul de build de la 18 minute la doar 40 de secunde când am mutat totul pe On-Demand în loc să le generăm pe toate la build time.
3. Pagina de produs (E-commerce cu catalog mare)
Alegere: ISR hibrid + generateStaticParams parțial.
Generăm la build doar top 500 cele mai vândute produse. Restul de 40.000 de pagini sunt generate on-first-request (folosind dynamicParams = true). Apoi le pui un revalidate = 3600 (o oră) ca să nu stresezi backend-ul. Trade-off: primul user care intră pe un produs obscur așteaptă 200-400ms în plus.
4. Stocul și Prețul pe pagina de produs
Alegere: Static Shell (ISR/SSG) + Client-side Fetching (SWR / React Query). Nu folosi ISR cu timp scurt (gen 5 secunde) pentru stocuri! Dacă ai un flash sale, vei servi informație veche (stale) fix când contează mai mult. Noi randăm pagina static pentru SEO și imagini, iar componentele de stoc și butonul de «Adaugă în coș» își fac fetch direct din API-ul de inventar pe client.
5. Dashboard-ul utilizatorului (Contul Meu / Analytics)
Alegere: Dynamic SSR (force-dynamic) sau Client-Side rendering complet.
Aici conținutul depinde 100% de cookie-ul de sesiune al userului. ISR sau SSG aici e o greșeală gravă de securitate – poți ajunge să faci cache la datele personale ale unui user și să le servești altuia (m-am lovit de un bug similar la un audit de securitate).
Trade-off-uri pe care nu ți le spune nimeni
ISR-ul clasic cu timp e comod, dar vine cu o problemă: Cache Poisoning temporar. Dacă backend-ul tău pică scurt timp de 10 secunde exact când Next.js încearcă să revalideze pagina în fundal, te trezești că Next.js memorează o pagină de eroare 500 sau o pagină goală pentru următoarea oră.
On-Demand e mult mai curat, dar necesită mai mult cod pe partea de infrastructură (webhook-uri securizate cu secret tokens, gestiune de erori).
Cum ați structurat caching-ul pe proiectele voastre mari de App Router? Ați avut probleme cu cache-ul de fetch din Next 14/15?