Aller au contenu principal
Site en cours de refonte — quelques pages peuvent bouger ou évoluer.
09 avril 2026

Vercel sert encore l’ancien code après un redeploy : le diagnostic qui évite de tourner en rond

Tu pushes, tu redeploy, tu forces un rebuild… et pourtant Vercel sert une version qui n’existe plus. Voilà comment je le prouve, puis comment je m’en sors sans tout casser.

12 min de lecture
54 vues
réactions
Partager :
Vercel sert encore l’ancien code après un redeploy : le diagnostic qui évite de tourner en rond

Si tu es ici, c’est que tu as vécu ce moment absurde : tu merges, Vercel déploie, le build passe, et le site sert encore une version ancienne. Pire, tu as parfois des erreurs qui ressemblent à « ce module importe un fichier supprimé », comme si le graphe de dépendances datait d’il y a deux commits. Et tu peux redeploy dix fois, ça ne bouge pas.

Dans la majorité des cas, ce n’est pas « Git qui n’a pas push », ni « Next qui n’a pas rebuild », ni « ton navigateur qui cache ». C’est un cache qui part en sucette quelque part dans la chaîne (artefacts de build, CDN, edge, ISR), et tant que tu n’as pas des preuves, tu vas juste te fatiguer à cliquer sur des boutons.

Les symptômes qui sentent le cache “stale/corrupted” (et pas un bug applicatif)

Le signe le plus net, c’est le décalage entre ce que tu vois dans les logs de build et ce qui est effectivement servi. Tu peux avoir un build qui affiche clairement le bon commit, des tests qui passent, une date de déploiement récente… et un navigateur (ou un curl) qui récupère un JS bundle d’hier.

Un autre symptôme très parlant côté Next, c’est la sensation de « graphe incohérent » : une preview qui tente de charger des chunks qui n’existent plus, des imports qui pointent vers des fichiers supprimés, ou des erreurs qui n’existent plus en local. Là, ça ne ressemble pas à une simple réponse CDN cachée. Ça ressemble à un artefact de build ou à un cache de compilation qui réutilise un état invalide.

Et le dernier truc qui met la puce à l’oreille : des previews qui divergent entre elles. Tu as deux URLs de déploiement censées représenter le même commit, et elles ne servent pas la même app. Si tu en es là, il faut arrêter de « tenter des rebuilds » et passer en mode enquête.

Avant d’accuser Vercel : les faux positifs qui te font perdre 2 heures

Le piège classique, c’est de confondre « ancien code » et « anciennes données ». Next (et l’écosystème React en général) te laisse empiler des caches à tous les étages : fetch mis en cache côté serveur, ISR (revalidate), edge cache, cache navigateur, cache Service Worker si tu en as un, sans parler d’un CDN externe si tu en as mis un devant. Résultat, tu peux avoir une page qui affiche des données “vieilles”, alors que le code a bien bougé.

Deuxième faux positif très courant : le navigateur. Pas juste le cache HTTP, mais aussi les scénarios où tu as un Service Worker, ou un PWA setup « oublié » qui sert des assets en offline-first. Si tu ne testes pas au minimum avec un curl (ou un autre navigateur, en navigation privée), tu peux accuser Vercel alors que tu t’auto-DDoS avec ton cache local.

Dernier faux positif : tu regardes la mauvaise URL. Entre le domaine de prod, les domaines d’alias, les preview URLs, les “branch deploys”, et parfois un domaine interne d’entreprise qui pointe sur autre chose, on voit vite des équipes comparer deux environnements différents en pensant comparer deux déploiements.

Diagnostic “preuve d’abord” : prouver quel build est réellement servi

Mon objectif n’est pas de « sentir » que ça ne bouge pas. C’est de pouvoir dire : « cette réponse vient de tel déploiement, elle sert tel commit, et elle passe (ou non) par tel cache ». Tant que tu ne sais pas ça, tu ne sais pas quoi purger.

Le plus rentable, c’est d’ajouter un build stamp visible quelque part (même temporairement). Typiquement un footer “Build: …” qui affiche un identifiant injecté au build. Sur Vercel, tu as souvent des variables d’environnement utiles (commit SHA, ID de déploiement) selon ton setup. Même si tu n’en as pas, tu peux injecter un timestamp de build dans une variable publique, juste pour la phase de diagnostic.

Si tu veux un truc bête et efficace, tu peux aussi renvoyer un header. Ça te permet de vérifier sans UI, et surtout de comparer rapidement preview/prod sur la même route.

// middleware.ts (Next.js)
import { NextResponse } from "next/server";

export function middleware(req) {
  const res = NextResponse.next();

  // À adapter à ton projet : l'idée est d'avoir un identifiant de build stable.
  // Tu peux injecter un GIT_SHA via ton pipeline si tu préfères.
  res.headers.set("x-build-stamp", process.env.VERCEL_DEPLOYMENT_ID ?? "unknown");
  return res;
}

Une fois que tu as ça, tu testes la même URL plusieurs fois, depuis ta machine et idéalement depuis un runner externe (un simple curl GitHub Actions ou un outil type reqbin) pour éviter l’effet « ça dépend de ma région / de mon PoP ». Et tu notes ce que tu observes, pas ce que tu espères.

Lire les headers Vercel/CDN : HIT, MISS, STALE… et les IDs qui disent la vérité

Vercel expose des headers qui aident justement à comprendre si tu es en train de taper du cache. Ce que je cherche en premier, c’est si la réponse vient d’un cache (HIT), si elle a été recalculée (MISS), ou si elle est servie en mode « pas frais mais tant pis » (STALE selon les cas et les routes).

Le réflexe utile : faire un HEAD (ou un GET léger) et capturer les headers. Tu vas souvent y voir un header de cache Vercel, un ID de requête, parfois un age, et d’autres indices qui te disent dans quel datacenter / quelle chaîne tu es passé. Ce n’est pas “magique”, mais c’est factuel.

# Remplace par ton URL (prod ou preview)
URL="https://ton-domaine-ou-ta-preview.vercel.app/"

# 1) Vérifie les headers de cache
curl -sI "$URL" | tr -d '\r'

# 2) Force une requête qui contourne certains caches intermédiaires
curl -sI -H "Cache-Control: no-cache" -H "Pragma: no-cache" "$URL" | tr -d '\r'

Ce que tu veux obtenir, c’est une cohérence entre ton x-build-stamp (ou ton footer) et le « comportement cache ». Si tu vois un stamp ancien alors que tu es sur une preview URL fraîchement créée, ça commence à sentir le souci d’artefacts ou d’assignation côté plateforme. Si tu vois un stamp qui change selon les requêtes, là tu es possiblement sur un problème de propagation / cache distribué.

À ce stade, garde une règle simple : si tu n’arrives pas à l’expliquer avec « cache HTTP normal », pense plutôt « un cache de build/artefacts » que « Vercel sert au hasard ». Ce n’est pas plus rassurant, mais ça oriente vers des actions concrètes.

Preview vs prod : comment je repère un artefact de build réutilisé alors qu’il ne devrait pas

Quand je soupçonne un cache de build corrompu (ou juste “stale”), je fais un test très terre-à-terre : je prends une route statique qui renvoie une page simple (ou une API route), et je compare la réponse entre deux déploiements différents, commit différent, URL différente. Si la réponse est identique alors que le code a changé, ce n’est plus un débat.

Ensuite je vais regarder les assets eux-mêmes. Sur Next, les fichiers sous /_next/static/ portent des hashes. Normalement, quand ton code change réellement, tu t’attends à voir bouger des noms de chunks, des références dans le HTML, etc. Si tu continues à recevoir des références vers des chunks “anciens” alors que le build a produit autre chose, tu as un décalage entre le résultat du build et ce qui est servi.

Dans les retours terrain récents, un suspect revient souvent : des caches liés à la compilation outillée (par exemple autour de Turbopack / du graphe de modules), qui peuvent se retrouver dans un état incohérent et être réutilisés sur des déploiements où tu t’attends à repartir propre. Je ne dis pas « c’est toujours ça ». Je dis que quand tu vois des modules qui « existent encore » alors que tu les as supprimés, ce type de cache est un candidat sérieux.

Plan de sortie gradué : retrouver un déploiement sain sans “tout cramer” au hasard

La première étape, c’est d’arrêter de redeploy en boucle. Ça te donne l’illusion d’agir, mais tu changes rarement les conditions du problème. Ce que tu veux, c’est forcer un chemin différent.

Je commence par la purge la plus “propre” côté Vercel : un redeploy en demandant explicitement un rebuild sans réutilisation des caches de build. Selon ton flow (UI ou CLI), l’idée est la même : tu veux casser la réutilisation d’artefacts. Si le déploiement redevient correct après ça, tu as déjà une info : le cache de build était dans l’équation.

Si ça ne suffit pas, je change volontairement quelque chose qui invalide très fort le build, mais sans toucher la logique produit. Par exemple, bump une dépendance mineure, changer un flag de build, ou modifier un fichier qui impacte forcément le bundling. C’est moche, oui. Mais c’est un test. S’il faut « secouer » le pipeline pour qu’il arrête de servir l’ancien monde, tu confirmes que tu n’es pas face à une simple incohérence locale.

Autre stratégie qui marche bien pour isoler : builder localement et déployer un artefact prébuildé (quand ton setup le permet). L’intérêt n’est pas d’adopter ça en prod. L’intérêt, c’est de prouver que « quand je fournis l’output moi-même, le problème disparaît » ou au contraire « même avec un output neuf, c’est encore vieux », ce qui pointe plus vers CDN/edge que vers compilation.

Enfin, si tu es dans un contexte Next où l’edge et l’ISR sont activés partout, j’ai déjà vu des équipes se piéger toutes seules. Elles croyaient “purger le code” alors qu’elles purgaient des pages régénérées à cadence lente. Là, le fix est conceptuel : remettre à plat où tu caches quoi, et arrêter d’avoir trois systèmes de cache qui se chevauchent sur les mêmes routes.

Éviter que ça revienne : arrête les clés de cache “magiques” et rends ton build observable

Le vrai problème avec les caches, ce n’est pas qu’ils existent. C’est qu’on les configure souvent comme un sortilège. Une clé « intelligente », une détection auto, un mode turbo, et on n’y touche plus. Jusqu’au jour où ça casse, et là plus personne ne sait quel cache est responsable.

Ce que je conseille aux équipes, c’est d’investir dans deux choses très simples. D’abord, un build stamp systématique (commit SHA, date, ID de déploiement) visible quelque part et récupérable en header. Ce n’est pas du vanity. C’est un outil de debug. Ensuite, un minimum d’archivage des logs de build et de la config effective (versions de Node, lockfile, variables critiques). Le jour où tu as un déploiement “impossible”, tu veux comparer des faits, pas des souvenirs.

Et si tu utilises des caches avancés (monorepo, remote cache, turbo, etc.), ne laisse pas l’équipe dans le flou. Documente ce qui est caché, où, et comment l’invalider proprement. Le bouton « force rebuild » est un dernier recours. Ce n’est pas une stratégie.

Quand escalader au support (et quoi fournir pour qu’on te prenne au sérieux)

Si tu as des preuves que la plateforme sert un artefact incohérent, tu vas gagner un temps fou en envoyant un dossier propre plutôt qu’un message « ça marche pas ». Ce que je fournis en général : l’URL exacte (preview et/ou prod), l’heure et le fuseau, les headers complets de la réponse, le x-build-stamp (ou le visuel du footer), et les IDs de requête renvoyés par Vercel.

Ajoute aussi les infos de déploiement côté Vercel (ID, commit attendu, logs du build) et un exemple minimal reproductible si tu peux. Pas un repo entier, juste la route qui montre le problème. Si le souci est intermittent, dis-le franchement et montre deux captures de headers qui divergent sur la même URL.

Dernière mise au point : si tu es en pleine crise et que ton site sert du code qui n’existe plus, pense aussi à l’option “mitigation” immédiate. Un domaine de secours, un rollback propre, ou même une bascule temporaire sur une version connue. Le debug parfait, tu le feras après. La priorité, c’est de reprendre le contrôle de ce que les utilisateurs reçoivent.

Conclusion : ton meilleur allié, c’est une preuve visible du build

Quand Vercel sert de l’ancien code, le danger ce n’est pas le bug en lui-même. C’est le temps que tu peux perdre à douter de tout, à toucher dix trucs à la fois, et à te retrouver sans savoir ce qui a “réparé”. Si tu retiens une seule idée, garde celle-là : rends ton build observable, lis les headers, compare des URLs, et avance par preuves.

Après ça, tu peux décider quoi faire calmement : purge ciblée, rebuild sans cache, simplification de ta stratégie ISR/edge, ou escalade support. Mais au moins, tu arrêtes de déployer à l’aveugle.

Sources

Cet article vous a plu ?

Commentaires

Laisser un commentaire

Entre 10 et 2000 caractères

Les commentaires sont modérés avant publication.

Aucun commentaire pour le moment.

Soyez le premier à donner votre avis !