Cache-Control et CDN : la stratégie de cache d’une landing page Next.js sur Vercel
Publié le 1 septembre 2026 · 8 min de lecture
Une landing page qui répond en 40 ms n’a, la plupart du temps, rien exécuté : elle a simplement été servie depuis un cache, quelque part entre le navigateur du visiteur et le serveur d’origine. C’est la manière la plus efficace de réduire le temps de réponse serveur (TTFB) — plus vite qu’en optimisant du code, puisqu’il n’y a simplement plus de code à exécuter. Mais « mettre en cache » recouvre en réalité trois mécanismes distincts, avec des règles et des risques différents. Les confondre produit deux symptômes opposés : un cache qui ne sert à rien parce qu’il est contourné à chaque requête, ou un cache qui sert la mauvaise réponse à la mauvaise personne.
Trois caches, trois rôles
Entre le clic sur une publicité et l’affichage de la landing page, une réponse HTML peut traverser jusqu’à trois couches de cache successives, chacune avec sa propre durée de vie et son propre déclencheur d’invalidation.
- Le cache du navigateur — stocké sur l’appareil du visiteur, il évite une requête réseau complète lors d’une deuxième visite. Réglé par l’en-tête
Cache-Controlrenvoyé par le serveur (max-age). - Le cache CDN (Vercel Edge Network) — une copie de la réponse posée sur des serveurs répartis géographiquement, entre le navigateur et la fonction serveur. C’est lui qui fait qu’un visiteur à Lyon reçoit la page depuis Paris et non depuis la région où l’application est déployée. Réglé par la directive
s-maxage, distincte demax-age. - Le cache interne de Next.js — le Full Route Cache (le HTML et le payload React déjà générés pour une route statique) et le Data Cache (le résultat d’un
fetchcôté serveur). C’est cette couche qui décide si une page est régénérée à chaque requête ou servie telle quelle depuis le dernier build.
Ces trois caches ne partagent ni la même durée de vie ni le même moyen d’invalidation : vider le cache CDN ne vide pas le cache navigateur d’un visiteur qui a déjà la page en local, et redéployer sur Vercel ne force pas immédiatement le rafraîchissement d’un cache navigateur réglé sur plusieurs heures. Une stratégie de cache cohérente règle les trois ensemble, pas une seule au hasard.
Ce qu’une landing page statique met déjà en cache, par défaut
Une landing page générée avec generateStaticParams — le cas de chaque page /templates/[slug] ou /blog/[slug] de ce site — est produite une fois au moment du build, puis servie telle quelle : HTML déjà écrit, aucune fonction serveur à exécuter à la requête. Sur Vercel, cette sortie statique est automatiquement posée sur le CDN avec un Cache-Control orienté vers un cache long à l’edge, invalidé uniquement par un nouveau déploiement. C’est la configuration la plus rapide possible et, pour une page dont le contenu ne change qu’au moment où on la modifie, la plus logique : rien ne justifie de régénérer un article de blog à chaque visite.
L’ISR : revalider sans reconstruire tout le site
Pour une donnée qui change entre deux déploiements — un prix, un stock, un compteur — la régénération statique incrémentale (ISR) reste la solution recommandée : la page continue à être servie depuis le cache tant que sa durée de revalidate n’est pas écoulée, puis Next.js la reconstruit en arrière-plan à la requête suivante, sans jamais reconstruire l’ensemble du site. L’article sur ISR et SSG pour un prix qui change détaille ce mécanisme et le cas de la revalidation à la demande (revalidateTag) ; l’essentiel à retenir ici est que l’ISR reste, à chaque instant, une réponse mise en cache — jamais un calcul en temps réel.
Piège n°1 : la personnalisation casse le cache — la camoufler est pire
Le problème n’est pas la personnalisation en soi, c’est où elle a lieu. Une landing page qui calcule une offre différente selon un cookie, une géolocalisation IP ou une session côté serveur ne peut plus être servie depuis un cache CDN classique : chaque visiteur devrait recevoir une réponse différente pour la même URL, ce que le CDN ne sait pas faire sans configuration spécifique (en-tête Vary, cache par clé de segmentation). Deux issues possibles, aussi mauvaises l’une que l’autre : soit le cache est désactivé et chaque visite réveille une fonction serveur — plus lent, plus coûteux en invocations — soit, pire, la réponse calculée pour le premier visiteur d’une fenêtre de cache est servie telle quelle à tous les suivants, offre expirée comprise, jusqu’à l’expiration du cache. C’est exactement le risque évité par la manière dont ce site calcule sa promotion de la semaine : le moteur de rotation d’offres (lib/promo.ts) est entièrement déterministe à partir de la date, mais le calcul se fait côté client, au montage du composant — jamais dans le rendu serveur. La page HTML reste 100 % statique et cacheable à l’edge sans limite ; c’est le navigateur, une fois la page chargée, qui affiche l’offre courante. Le compte à rebours est réel, jamais une fausse rareté, et le cache n’a jamais à choisir entre lenteur et fraîcheur.
Piège n°2 : un cache mal réglé peut exposer la réponse d’un visiteur à un autre
Le risque inverse, plus grave, est documenté sous le nom de web cache deception : un CDN met en cache une réponse censée être privée — parce qu’une confusion de chemin (une extension de fichier statique ajoutée à une route dynamique, par exemple) le fait passer pour une ressource publique et cacheable — puis sert cette réponse à n’importe quel visiteur suivant qui redemande la même URL. Une étude de Mirheidari et al. (« Cached and Confused: Web Cache Deception in the Wild ») a mesuré cette vulnérabilité à grande échelle et l’a trouvée exploitable sur une part significative des sites testés, y compris de grandes plateformes. Sur une landing page, la surface d’exposition est réduite — pas de compte utilisateur — mais elle existe dès qu’une route sert une réponse liée à une session ou à un token, comme /api/download avec son jeton de téléchargement : ces routes doivent explicitement renvoyer Cache-Control: private, no-store et ne jamais être laissées au réglage par défaut du CDN.
Cheat-sheet Cache-Control
| Directive | Rôle | Exemple d’usage |
|---|---|---|
public | Autorise la mise en cache par un cache partagé (CDN) | Page statique, image, police |
max-age | Durée de fraîcheur pour le cache navigateur | max-age=3600 sur une image OG |
s-maxage | Durée de fraîcheur pour le cache CDN, prioritaire sur max-age | s-maxage=31536000 sur une page statique buildée |
stale-while-revalidate | Sert une version périmée pendant la revalidation en arrière-plan | Cas typique de l’ISR sous Next.js |
private | Interdit tout cache partagé, autorise seulement le navigateur | Route liée à une session |
no-store | Interdit toute mise en cache, à toute couche | /api/download, formulaire avec token |
Pourquoi ça compte : la vitesse perçue a des seuils, pas une échelle continue
L’intérêt du cache n’est pas seulement le chiffre affiché dans un outil de mesure : c’est de franchir des seuils psychologiques documentés depuis plus d’un demi-siècle. Dans une étude fondatrice de 1968 encore largement citée en ergonomie logicielle, Robert B. Miller (« Response Time in Man-Computer Conversational Transactions ») distingue trois paliers : en dessous de 0,1 seconde, une réponse est perçue comme instantanée ; en dessous d’une seconde, l’enchaînement des actions reste perçu comme continu, sans rupture de concentration ; au-delà de dix secondes, l’attention se détourne. Une réponse servie depuis le cache CDN de Vercel se compte en dizaines de millisecondes ; une réponse qui traverse une fonction serveur, une résolution DNS à froid et une connexion TLS peut facilement dépasser la seconde sur un premier chargement. Ce n’est pas une nuance cosmétique : c’est la différence entre une page qui « répond » et une page qui « charge ».
Concrètement, sur Vercel
- Laisser les pages statiques (
/templates/[slug],/blog/[slug]) sansrevalidateni appel àcookies()/headers()dans le rendu : Next.js les traite comme entièrement statiques et Vercel les pose sur l’edge sans limite de durée, invalidées au prochain déploiement. - Ajouter un
revalidate(en secondes) uniquement là où une donnée change réellement entre deux déploiements — jamais « par précaution » sur une page qui ne bouge pas, ce qui ne ferait que réintroduire un aller-retour serveur inutile. - Garder toute personnalisation réellement dépendante du visiteur (offre, langue détectée, statut de connexion) côté client, après le premier rendu — pas dans le rendu serveur d’une page destinée à rester statique.
- Passer explicitement en
Cache-Control: private, no-storetoute route qui renvoie une donnée liée à une session, un token ou un email — jamais laissée au comportement par défaut d’un cache partagé.
Une bonne stratégie de cache ne se voit jamais directement dans le design d’une landing page — elle se voit dans le temps de chargement, dans la facture d’hébergement, et dans l’absence totale d’incident du type « la mauvaise personne a vu la mauvaise offre ». C’est le genre de détail technique qui ne convertit personne à lui seul, mais qui conditionne silencieusement tous les indicateurs qui, eux, convertissent. Les templates LanderKit (89 € l’unité, 229 € le pack de 10) sont livrés comme des projets Next.js statiques par défaut, pensés pour être déployés sur Vercel sans réglage de cache à improviser — la personnalisation ponctuelle (compte à rebours, offre de la semaine) reste toujours côté client, pour ne jamais avoir à choisir entre un cache rapide et un cache fiable.
FAQ
Questions fréquentes
Quelle est la différence entre max-age et s-maxage ?
max-age règle la durée de fraîcheur pour le cache du navigateur du visiteur. s-maxage fait la même chose pour un cache partagé comme un CDN, et est prioritaire sur max-age pour ces caches-là : on peut par exemple garder une page longtemps en cache côté CDN tout en forçant une revalidation plus fréquente côté navigateur.
Une landing page statique Next.js est-elle automatiquement mise en cache sur Vercel ?
Oui, tant que la page n'appelle pas cookies(), headers() ou une donnée dynamique par requête dans son rendu serveur : Next.js la traite comme statique, et Vercel la sert depuis son réseau CDN sans exécuter de fonction serveur, jusqu'au prochain déploiement ou à la revalidation configurée.
Pourquoi ne pas simplement personnaliser chaque page côté serveur pour chaque visiteur ?
Parce que cela rend la page impossible à mettre en cache normalement à l'edge : soit chaque visite déclenche une fonction serveur (plus lent, plus coûteux), soit la première réponse calculée est mise en cache et servie à tort à tous les visiteurs suivants. Calculer la personnalisation côté client après le premier rendu évite ce compromis.
Qu'est-ce que le web cache deception et une landing page y est-elle exposée ?
C'est une faille où un cache CDN met en cache par erreur une réponse censée rester privée, puis la sert à d'autres visiteurs. Une landing page classique y est peu exposée en l'absence de compte utilisateur, mais toute route liée à un token (comme un lien de téléchargement) doit explicitement porter Cache-Control: private, no-store pour rester hors de portée d'un cache partagé.
À lire ensuite
Articles liés
- Géolocalisation IP sur une landing page : personnaliser sans fausser le SEO ni effrayer le visiteurDétecter la ville d’un visiteur depuis son adresse IP et adapter le titre, la devise ou un témoignage local en conséquence : la promesse est séduisante, mais la géolocalisation IP est moins précise qu’on le croit, et personnalisée sans précaution elle peut se transformer en cloaking aux yeux de Google. Ce que cette technique permet vraiment, comment la poser proprement en Next.js sur Vercel, et où s’arrêter.
- De Figma à une landing page Next.js : ce qui se perd toujours dans la traductionUne maquette validée en réunion, puis une landing page livrée qui n'a plus tout à fait le même rendu : espacements resserrés, police de secours qui s'affiche une seconde de trop, bouton qui ne réagit pas comme sur le prototype. Ce n'est pas un accident isolé — c'est un écart mesuré dans la recherche sur le travail de conception, et il existe des façons concrètes de le réduire.
- Déployer sa landing page Next.js sur Vercel : le guide pas à pasUn template Next.js acheté ne convertit personne tant qu’il n’est pas en ligne. Guide pas à pas pour le déployer gratuitement sur Vercel : dépôt Git, premier déploiement, domaine personnalisé et mises à jour automatiques.