Aller au contenu
Fangfang Chen
← Retour au journal

Autrice: Fangfang Chen · Ingénierie · 4 novembre 2026

Déployer Next.js sur Cloudflare, sans Vercel

De Pages à Workers, la comptabilité du bundle et les limites qui comptent vraiment.


Le premier déploiement Cloudflare n'a pas échoué parce que le code était trop lent. Il a échoué parce que la build était comptée dans la mauvaise unité.

VieauQc a démarré sur Cloudflare Pages avec next-on-pages. La build des Pages Functions a atteint 27 255 196 octets — environ 25,99 MiB — contre une limite de 25 MiB en octets bruts. La même build ne faisait que 6,43 MiB gzippés. Sur Workers, c'est la taille compressée qui comptait. Cette différence a déclenché la migration de Pages vers Workers avec OpenNext le 16 juillet 2026. Ce n'était pas un départ de Vercel ; Vercel n'a jamais été l'hébergeur de production.

La première build OpenNext faisait 5,47 MiB gzippés. À la mi-septembre, elle était à 9,42 MiB, soit 94,2 % de l'ancienne limite payante de 10 MB. Puis Cloudflare a changé la règle : depuis le 4 septembre 2026, seule la taille non compressée compte, avec une limite de 64 MiB et un démarrage sous une seconde. Le démarrage mesuré était de 27 ms. La contrainte s'est déplacée, mais elle n'a pas disparu.

Le 12 octobre, le déploiement faisait 50,57 MiB, soit 79 % de la nouvelle limite. La répartition était plus utile que le total : environ 12,93 MiB de manifestes client répétés par route, 21,35 MiB de chunks partagés, 5,77 MiB de code de page, 2,25 MiB de runtime Next, et environ 9,8 MiB de corps de guides dans les chunks.

Deux leçons sont sorties de cette enquête.

Premièrement, import() dynamique ne retire pas le code du bundle Worker. Il contrôle quand le code s'exécute, pas s'il est expédié. Les modules de guides étaient déjà chargés par import dynamique ; ils comptaient quand même.

Deuxièmement, les gains durables sont venus du déplacement des données et de l'emballage, pas de l'ajout de fonctionnalités du framework. Les dialogues et le glossaire ont été déplacés vers R2 en mai 2026. Les corps des actualités ont suivi le 8 août. La grammaire et les lectures ont été déplacées le 2 septembre. Les corps des guides sont encore dans le bundle Worker, et c'est pourquoi ils restent le plus gros bloc.

Le correctif d'emballage le moins cher a été une ligne : "minify": true dans wrangler.jsonc. Wrangler re-emballait la sortie OpenNext déjà compressée sans minification, ce qui ajoutait environ 7,3 MiB. Le déploiement est passé de 50,71 MiB à 43,36 MiB le 13 octobre. Au 4 novembre, le journal indique 48,405 MiB, soit 75,6 % de la limite de 64 MiB.

D'autres règles opérationnelles comptent autant que le bundle :

  • Les variables d'environnement sont séparées entre build et runtime. Un worktree obsolète a déjà intégré une clé Clerk de développement dans la production et renvoyé HTTP 500 sur toutes les pages. La build échoue maintenant si les valeurs de build requises manquent ou si une clé pk_test_ apparaît.
  • Le contenu R2 est synchronisé séparément du code. Un déploiement ne pousse ni l'audio ni les corps d'articles. Quand la synchronisation est manquée, des pages peuvent s'afficher avec des corps vides et aucune erreur. C'est arrivé le 13 août, le 29 octobre et le 3 novembre 2026.
  • Le déploiement est manuel depuis main. Un git push ne déploie pas.

Rien de tout cela n'est propre à Next.js. C'est le travail ordinaire de mettre une application riche en contenu sur un runtime en périphérie : décider ce qui est du code, ce qui est des données, ce qui est construit et ce qui est récupéré. Le déploiement est ennuyeux maintenant, et c'est précisément le but.