Salta al contenuto

Cache-Control: come funziona l’header e quali direttive scegliere

Foto Autore
Contenuto a cura di Roberto Varriale Aggiornato il 17 Ottobre 2026 · Lettura: 12 min

Cache-Control funziona come header HTTP con cui il server comunica a browser e cache condivise se, dove e per quanto tempo possono riutilizzare una risorsa senza richiederla di nuovo, tramite direttive che ne regolano durata e ambito di memorizzazione.

Cache-Control è l’header HTTP con cui un server dice a browser e cache condivise (CDN, proxy) se, dove e per quanto tempo possono riutilizzare una risorsa senza richiederla di nuovo. Fa parte dell’Hypertext Transfer Protocol e sostituisce, nella pratica, il vecchio header Expires.

Cache-Control in sintesi

  • Cosa controlla: stabilisce se una risposta può essere salvata, da chi (solo il browser o anche una cache condivisa) e per quanto tempo resta considerata valida.
  • Direttive principali: max-age e s-maxage fissano la durata, public e private decidono chi può salvare, no-cache e no-store decidono se e come va rivalidata.
  • Rischio opposto: troppo poco caching allunga i tempi di caricamento, troppo caching mostra contenuti vecchi agli utenti dopo un aggiornamento.
  • Dati sensibili: pagine con informazioni personali o di pagamento vanno marcate no-store, non semplicemente no-cache.
  • Dove si configura: sul server o sulla CDN, non nel codice HTML della pagina (il meta tag http-equiv ha effetto limitato e inaffidabile).
  • Standard di riferimento: il comportamento è definito dall’RFC 9111 ‘HTTP Caching’, pubblicato nel giugno 2022.

Come si scrive l’header e cosa sono fresh e stale

L’header si scrive come una lista di direttive separate da virgola, ad esempio Cache-Control: max-age=3600, public. Le direttive sono case-insensitive ma in minuscolo, perché alcune implementazioni più vecchie non riconoscono le maiuscole.

Prima di entrare nelle singole direttive, vale la pena fissare due termini che in giro si usano in modo impreciso. Una risposta è fresh (fresca) finché resta dentro il tempo indicato da max-age o s-maxage: in quella finestra la cache la riusa senza contattare il server. Diventa stale (scaduta) dopo, e a quel punto, salvo diverse indicazioni, la cache dovrebbe rivalidarla con una richiesta condizionale prima di riproporla. La differenza tra queste due parole spiega da sola buona parte dei comportamenti che si vedono in produzione, inclusi quelli che sembrano bug e non lo sono.

Cache condivisa
Cache tra il server di origine e l’utente, come una CDN o un proxy: serve la stessa risposta a più persone.
Cache privata
Cache dentro il browser dell’utente, usata solo per quel singolo utente.
Revalidation
Richiesta con cui la cache chiede al server di origine se la copia salvata è ancora valida, invece di scaricarla da zero.
Diagramma che mostra un file che resta valido in cache per un numero di secondi prima di tornare al server
Il tempo indicato da max-age parte dalla generazione della risposta sul server, non dal momento in cui il browser la riceve.

Quanto tempo tenere una risorsa in cache: max-age e s-maxage

max-age=N dice per quanti secondi la risorsa resta fresca per qualunque cache, incluso il browser. s-maxage=N fa la stessa cosa ma solo per le cache condivise, e quando è presente sovrascrive max-age per CDN e proxy, lasciando al browser il valore di max-age.

Un dettaglio che nei materiali tecnici si perde facilmente: il conteggio di max-age parte da quando il server ha generato la risposta, non da quando il browser l’ha ricevuta. Se una CDN ha già tenuto la risposta in cache per un certo tempo (indicato dall’header Age), il browser deve sottrarre quel tempo dalla propria finestra di freschezza.

Se devi scegliere una durata: parti dal tipo di risorsa

  1. Se il file ha un nome con hash di versione (es. main.abc1234.js): usa una durata lunghissima, anche un anno, perché un cambiamento del contenuto genera un nuovo URL.
  2. Se è una pagina di blog o una scheda prodotto aggiornata di rado: una durata di ore o giorni è ragionevole.
  3. Se è una homepage o una pagina che cambia più volte al giorno: una durata di pochi minuti, oppure no-cache con rivalidazione.
  4. Se serve una durata diversa per browser e CDN: combina max-age e s-maxage nello stesso header, ad esempio max-age=600, s-maxage=3600.

Un valore negativo o non intero per max-age (ad esempio -1 o 3599,99) non è previsto dalla specifica: il comportamento non è definito, e la maggior parte delle cache lo tratta come se fosse 0, cioè risorsa già scaduta. Non è un’impostazione da usare di proposito, è un errore di configurazione da evitare.

No-cache e no-store: la confusione più diffusa

No-cache non significa “non salvare”: la risorsa può restare in cache, ma va rivalidata con il server a ogni riutilizzo, anche se la cache è temporaneamente scollegata dal server di origine. No-store, invece, vieta qualunque memorizzazione, piena e semplice, da parte di qualsiasi cache.

La prima volta che ho letto no-cache ho pensato significasse “butta via tutto”: è il fraintendimento più comune in questo campo, e l’equivoco nasce dal nome della direttiva, non dal suo comportamento reale.

Confronto tra no-cache e no-store
Direttiva La risorsa viene salvata? Serve rivalidare? Quando usarla
no-cache Sì Sì, a ogni richiesta Contenuto che cambia spesso ma non è sensibile: notizie, liste prodotti popolari
no-store No Non applicabile Dati sensibili: pagine di pagamento, saldo conto, dati personali

Se la cache è scollegata dal server: must-revalidate decide cosa fare

Con must-revalidate, una volta che la risposta diventa stale, la cache non può riproporla senza prima averla validata: se il server non è raggiungibile, la richiesta restituisce un errore 504 (Gateway Timeout) invece di servire una copia vecchia. Senza must-revalidate, HTTP permette alle cache di servire comunque una risposta scaduta quando sono scollegate dall’origine. Proxy-revalidate fa la stessa cosa di must-revalidate, ma si applica solo alle cache condivise, non al browser.

Un caso che quasi nessuna guida segnala: né no-cache né must-revalidate garantiscono la rivalidazione quando l’utente naviga con i pulsanti avanti e indietro del browser. Se il browser usa il back/forward cache (bfcache), ripristina uno snapshot della pagina senza passare dal controllo che queste direttive impongono.

Public e private: chi può memorizzare la risposta

Public dichiara che la risposta può essere salvata da qualunque cache, anche se normalmente non lo sarebbe (ad esempio perché associata ad autenticazione HTTP). Private limita la memorizzazione al solo browser dell’utente: una CDN o un proxy pubblico non devono salvarla.

La mia posizione è semplice: ogni contenuto generato dopo un login, o legato a una sessione utente tramite cookie, va marcato private. Se te ne dimentichi, quella risposta personalizzata può finire in una cache condivisa e arrivare a un altro utente al posto tuo. Non è un’ipotesi remota, è il comportamento previsto se non specifichi nulla: quando public e private sono assenti, il default più comune è public, ma browser e CDN applicano anche euristiche proprie, quindi su contenuti personalizzati non conviene lasciare la scelta al caso.

Immutable e stale-while-revalidate: le direttive meno note

Immutable dice alla cache che la risposta non cambierà per tutta la sua durata di freschezza, quindi non serve nemmeno controllare se è cambiata quando l’utente ricarica la pagina. Ha senso solo su asset con hash di versione nel nome del file, abbinata a un max-age molto lungo.

Stale-while-revalidate permette di servire subito la copia scaduta mentre, in background, la cache scarica quella aggiornata: l’utente vede una pagina veloce anche se non è l’ultimissima versione, e il contenuto fresco arriva alla richiesta successiva. Stale-if-error fa qualcosa di simile ma solo quando il server di origine risponde con un errore: in quel caso la cache preferisce servire una copia vecchia piuttosto che mostrare un errore all’utente.

Cache-Control ed Expires: perché uno ha sostituito l’altro

Expires indica una data e un’ora assolute di scadenza; Cache-Control usa secondi relativi al momento della generazione della risposta, il che evita i problemi di sincronizzazione tra orologi di client e server che Expires può avere. Quando sono presenti entrambi, le direttive di Cache-Control (max-age o s-maxage) hanno la priorità su Expires: in pratica oggi Expires resta solo come fallback per i client più vecchi che non riconoscono Cache-Control.

Le regole di base del caching HTTP, inclusa questa priorità, sono definite dall’RFC 9111 “HTTP Caching”, pubblicato nel giugno 2022; esiste anche un RFC 9213 ‘Targeted HTTP Cache Control’ (2022) per direttive mirate a specifiche cache condivise, pensato per scenari con più CDN sullo stesso percorso.

Tre tipi di file - script con hash, pagina prodotto, pagina di pagamento - ciascuno con un'etichetta di configurazione diversa
Ogni tipo di risorsa richiede una combinazione diversa di direttive, non un’unica impostazione per tutto il sito.

Esempi di configurazione per tipo di risorsa

Non esiste un header Cache-Control giusto per tutto il sito: dipende da chi deve poter riusare quella risorsa e per quanto tempo. Questi sono gli scenari più comuni che un titolare di sito o di e-commerce incontra davvero.

Configurazioni di Cache-Control per scenario
Tipo di risorsa Header consigliato Perché
File statico con hash nel nome (JS, CSS, immagini versionate) public, max-age=31536000, immutable Il contenuto non cambia: un aggiornamento genera un nuovo URL
Pagina prodotto o articolo di blog public, max-age=3600 Contenuto condiviso tra tutti gli utenti, aggiornato di rado
Pagina account, carrello, risultati personalizzati no-cache, private Contenuto specifico per l’utente, va rivalidato a ogni accesso
Pagina di pagamento o dati bancari no-store Nessuna copia deve restare in nessuna cache

Nel codice del sito, il valore corretto si imposta sul server (Apache, Nginx) o sulla configurazione della CDN, non con un meta tag nella pagina HTML: il meta http-equiv per la cache ha un supporto parziale e inaffidabile nei browser moderni. Se gestisci un hosting condiviso, verifica con il fornitore come impostare gli header di risposta prima di modificare il codice dell’applicazione.

Cache-Control e la cache che l’utente vede nel browser: cosa cambia

Cache-Control è l’impostazione che decidi tu come gestore del sito; la cache del browser è l’effetto di quella impostazione lato utente, insieme alle decisioni del browser stesso. Quando un visitatore vede una versione vecchia della tua pagina dopo un aggiornamento, nella maggior parte dei casi la causa è un max-age troppo lungo impostato sul server, non un problema del browser dell’utente.

Un utente può sempre forzare lo svuotamento della propria cache dalle impostazioni del browser, nella sezione privacy: questo risolve il sintomo per quel singolo utente, ma non la causa, che resta nella configurazione del tuo server. Cache e cookie sono due cose diverse: la cache salva file per velocizzare il caricamento, i cookie salvano dati di sessione e preferenze; svuotare l’una non elimina necessariamente gli altri, dipende dalle opzioni selezionate nel pannello di eliminazione dati del browser.

Vantaggi e limiti di una cache condivisa ben configurata

Una cache condivisa riduce il carico sul server di origine e abbassa i tempi di caricamento percepiti, perché molti utenti ricevono la stessa risposta senza una nuova richiesta all’origine. Il limite principale riguarda la privacy: i browser moderni partizionano la cache per dominio richiedente, e questo partizionamento fa aumentare il tasso di mancate corrispondenze della cache di circa il 3,6%, secondo i dati di Partizionamento della cache per maggiore sicurezza e privacy (2020).

Lo stesso studio misura un impatto modesto sulle prestazioni percepite, con variazioni del First Contentful Paint di circa lo 0,3%, a fronte di un aumento della frazione di byte caricati dalla rete di circa il 4%. In pratica: la protezione della privacy costa qualche richiesta in più alla rete, non un rallentamento percepibile dall’utente. È un trade-off che vale la pena conoscere prima di dare per scontato che “più cache” significhi sempre “sito più veloce”.

Errori frequenti nella configurazione di Cache-Control

Gli errori che vedo più spesso non riguardano la sintassi, ma la logica con cui si sceglie la direttiva.

Se imposti lo stesso max-age su tutto il sito

Un valore unico per pagine statiche e pagine dinamiche è quasi sempre sbagliato: o tieni troppo a lungo contenuti che cambiano, o rinunci a cache utile su file che non cambiano mai.

Se usi no-cache invece di no-store su dati sensibili

No-cache consente comunque il salvataggio della risposta, con l’obbligo di rivalidarla: per dati bancari o personali non basta, serve no-store, perché quella copia non deve esistere da nessuna parte oltre al server di origine.

Se dimentichi private su contenuti personalizzati

Una risposta personalizzata senza private può finire salvata in una CDN o in un proxy pubblico e servita a un altro utente: è l’errore con l’impatto più serio sulla privacy tra quelli elencati qui.

Diffido di chi vende configurazioni di cache “universali, valide per ogni sito”: la direttiva corretta dipende dal tipo di risorsa, e una checklist generica non sostituisce la verifica diretta degli header di risposta.

Domande frequenti su Cache-Control

Cos’è l’header Cache-Control

È l’header HTTP di richiesta o risposta che indica se una risorsa può essere salvata in cache, da chi (browser o cache condivisa) e per quanto tempo resta considerata valida prima di dover essere rivalidata con il server di origine.

Qual è la differenza tra no-cache e no-store

No-cache permette di salvare la risorsa ma impone di rivalidarla a ogni uso; no-store vieta qualunque memorizzazione. Si usa no-store per dati sensibili, no-cache per contenuti che cambiano spesso ma non sono riservati.

A cosa serve s-maxage rispetto a max-age

Max-age vale per qualunque cache, incluso il browser; s-maxage vale solo per le cache condivise come le CDN e, quando è presente, sovrascrive max-age per quelle cache specifiche.

Cache-Control sostituisce l’header Expires

Nella pratica sì: quando entrambi sono presenti, le direttive di Cache-Control hanno la priorità su Expires, che resta solo come riferimento per client che non riconoscono Cache-Control.

Perché vedo ancora la versione vecchia di un sito dopo un aggiornamento

Nella maggior parte dei casi la causa è un max-age troppo lungo impostato sul server per quella risorsa, non un problema del browser: la correzione va fatta nella configurazione del sito, non solo svuotando la cache locale.

No: la cache salva file per velocizzare il caricamento delle pagine, i cookie salvano dati di sessione e preferenze. Nel pannello di eliminazione dati del browser sono quasi sempre due opzioni separate.

Quando ha senso usare immutable

Solo su asset statici con un hash di versione nel nome del file, abbinata a un max-age molto lungo: segnala che quella specifica risorsa non cambierà mai durante la sua validità, evitando controlli di rivalidazione inutili.

Fonti e riferimenti

Questo contenuto ti ha aiutato?

Ti è stato utile questo articolo?

Aiuta altri professionisti a crescere. Condividi questo contenuto con il tuo network.

Iscriviti alla Newsletter

Ricevi una sola mail a settimana con strategie, casi studio e consigli pratici per scalare la tua impresa. Zero spam, promesso.

Quanto fa + ?

Roberto
Varriale

In quasi 20 anni ho aiutato oltre 700 Micro Imprese a migliorare il ROI aumentando Vendite e clienti con il Traffico Organico.

Chi Sono

"Se questa risorsa ti è stata utile, valuta se seguirmi anche nei social sia l'investimento di tempo migliore che tu possa fare adesso."

Roberto Varriale