Next.js : build et déploiement
Noms génériques : application monapp, utilisateur monapp, dossier /srv/monapp, port local 3000, domaine exemple.com.
Modes de sortie
Section intitulée « Modes de sortie »| Mode | output |
Résultat | Serveur Node.js |
|---|---|---|---|
| Serveur (défaut) | (rien) | .next/ + next start |
Oui |
| Autonome | 'standalone' |
Dossier minimal exécutable avec node |
Oui |
| Export statique | 'export' |
Fichiers HTML dans out/ |
Non |
L’export statique n’est possible que sans fonctions serveur (pas de route handler, de Server Action, de rendu à la demande, d’optimisation d’images à la volée).
Construire
Section intitulée « Construire »npm cinpm run buildLa sortie du build liste chaque route avec ○ (statique), ● (statique avec paramètres générés) ou ƒ (dynamique, rendue à chaque requête). Un build qui échoue signale en général une erreur de types, de lint ou de données.
Déploiement autonome (standalone)
Section intitulée « Déploiement autonome (standalone) »next.config.ts :
const config: NextConfig = { output: 'standalone', poweredByHeader: false };export default config;Après npm run build, le dossier .next/standalone/ contient un serveur minimal avec ses dépendances. Il faut y copier les assets :
cp -r public .next/standalone/publicmkdir -p .next/standalone/.nextcp -r .next/static .next/standalone/.next/static
cd .next/standaloneHOSTNAME=127.0.0.1 PORT=3000 node server.jsDéployer ce dossier sur le serveur :
rsync -az --delete --dry-run .next/standalone/ utilisateur@serveur.exemple.com:/srv/monapp/app/rsync -az --delete .next/standalone/ utilisateur@serveur.exemple.com:/srv/monapp/app/Lire la sortie du --dry-run. Le dossier standalone est déjà autonome : pas besoin de node_modules sur le serveur (sauf éléments natifs : construire sur une machine de même architecture et même système que le serveur).
Service systemd
Section intitulée « Service systemd »/etc/monapp.env (droits 640) :
NODE_ENV=productionHOSTNAME=127.0.0.1PORT=3000DATABASE_URL=postgres://app@127.0.0.1:5432/boutique/etc/systemd/system/monapp.service :
[Unit]Description=Application Next.js monappAfter=network.target
[Service]User=monappGroup=monappWorkingDirectory=/srv/monapp/appEnvironmentFile=/etc/monapp.envExecStart=/usr/bin/node server.jsRestart=on-failureRestartSec=3NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=trueReadWritePaths=/srv/monapp
[Install]WantedBy=multi-user.targetsudo adduser --system --group --home /srv/monapp monappsudo systemctl daemon-reloadsudo systemctl enable --now monappcurl -I http://127.0.0.1:3000/sudo journalctl -u monapp -fLe service doit pouvoir écrire dans le dossier de cache de Next.js (.next/cache : images optimisées, pages revalidées) : d’où ReadWritePaths. Voir systemd : écrire un service, durcissement et Node.js : mise en production. Avec PM2 : PM2 : démarrage automatique.
Reverse proxy Caddy
Section intitulée « Reverse proxy Caddy »exemple.com { encode zstd gzip
@statiques path /_next/static/* header @statiques Cache-Control "public, max-age=31536000, immutable"
header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" Referrer-Policy "strict-origin-when-cross-origin" -Server }
reverse_proxy 127.0.0.1:3000}
www.exemple.com { redir https://exemple.com{uri} permanent}Les fichiers de /_next/static/ ont un nom avec empreinte : cache durable. Voir Caddy : exemples réutilisables et, pour le pare-feu, Exemple : VPS avec Caddy.
Export statique
Section intitulée « Export statique »const config: NextConfig = { output: 'export', images: { unoptimized: true }, trailingSlash: true,};npm run build # produit out/rsync -az --delete out/ utilisateur@serveur.exemple.com:/var/www/monsite/Servi comme n’importe quel site statique (voir Astro : rendu et déploiement pour un exemple de bloc Caddy avec page 404).
Variables d’environnement
Section intitulée « Variables d’environnement »NEXT_PUBLIC_*: intégrées au build (reconstruire pour les changer).- Les autres : lues à l’exécution par le serveur (
/etc/monapp.env). - Aucun secret dans
NEXT_PUBLIC_*ni dans le dépôt.
Mise à jour sans interruption longue
Section intitulée « Mise à jour sans interruption longue »# sur la machine de buildnpm ci && npm run buildrsync -az .next/standalone/ utilisateur@serveur.exemple.com:/srv/monapp/app.nouvelle/# sur le serveursudo systemctl stop monappmv /srv/monapp/app /srv/monapp/app.ancienne && mv /srv/monapp/app.nouvelle /srv/monapp/appsudo systemctl start monappcurl -fsS http://127.0.0.1:3000/ >/dev/null && echo OKGarder l’ancienne version pour un retour arrière rapide (mv inverse). Pour un rechargement sans coupure avec plusieurs instances : PM2 : mode cluster et reload.
Plusieurs instances et cache
Section intitulée « Plusieurs instances et cache »Le cache de Next.js (pages revalidées, fetch) est par instance et stocké sur le disque local : avec plusieurs instances ou plusieurs serveurs, chaque instance a son propre cache, ce qui peut donner des réponses différentes. Pour un cache partagé, configurer un gestionnaire de cache personnalisé (voir la documentation cacheHandler).
Liste de contrôle
Section intitulée « Liste de contrôle »output: 'standalone'et copie depublic/et.next/static.- Service avec un utilisateur dédié et des droits d’écriture sur le cache.
- Écoute sur
127.0.0.1, reverse proxy HTTPS. - Cache long sur
/_next/static/*seulement. - Pas de secret dans
NEXT_PUBLIC_*. - Journaux :
journalctl -u monapp.
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
502 |
Service arrêté ou mauvais port : systemctl status monapp, curl http://127.0.0.1:3000 |
| Styles et images manquants | .next/static et public non copiés dans standalone |
| Le service redémarre en boucle | journalctl -u monapp -n 50 : variable manquante, port occupé, fichier server.js absent |
EACCES dans .next/cache |
Droits d’écriture de l’utilisateur du service |
HOSTNAME ignoré (écoute sur toutes les interfaces) |
Définir HOSTNAME=127.0.0.1 dans l’environnement du service |
| Le build échoue sur le serveur (mémoire) | Construire ailleurs (poste, CI), NODE_OPTIONS=--max-old-space-size=4096 |
Variable NEXT_PUBLIC_* obsolète |
Reconstruire |
Erreur sharp sur le serveur |
Architecture ou système différents de la machine de build |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Aucune propre à Next.js. Le chemin de node (which node) dépend de l’installation ; construire avec la même version majeure de Node.js que celle du serveur.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Déploiement, Sortie standalone
- Suite : Dépannage