Skip to main content

Le principe à retenir

Deux apps, deux moments de lecture de l’env différents. C’est la source de 90 % des « ça marche en local mais plante en prod ».
Les deux valident via @t3-oss/env-core : une var required manquante ou malformée fait crasher au démarrage avec ❌ Invalid environment variables.

API — env lue au runtime

Le bundle dist/server.js lit Bun.env au démarrage. Les valeurs doivent donc être injectées dans l’environnement runtime du conteneur (docker run -e …, ou l’onglet Environment de Dokploy).
Ne pas déclarer ces vars en ARG dans le Dockerfile. En voyant un ARG DATABASE_URL, Dokploy les classe en build-args et ne les injecte plus au runtimeundefined au boot. L’API n’a besoin d’aucune var au build (runtimeEnv: Bun.env est lu au runtime).

Apps Vite — env inlinée au build

Vite remplace import.meta.env.VITE_OPEN_URL par sa valeur littérale pendant vite build. Conséquence :
  • Fournir une VITE_* en env runtime sur Dokploy → inutile, le client ne lit jamais l’env au runtime.
  • Il faut la passer en build arg, et que le Dockerfile déclare le ARG correspondant pour la capter.
Ajouter une VITE_* au schéma env.ts sans ajouter son ARG au Dockerfile → Vite l’inline à undefined → crash runtime. Les deux vont toujours ensemble.

Pièges Docker communs

Guillemets dans le .env

docker run --env-file (et Dokploy) ne strippent pas les guillemets, contrairement à Bun/dotenv en local. DATABASE_URL="postgres://…" devient littéralement "postgres://…"Invalid URL.
Ne jamais quoter les valeurs dans l’env passé à Docker/Dokploy.

ENV ne traverse pas les stages

Chaque FROM … AS … repart d’un environnement vierge. Un ENV NODE_ENV=production dans le stage installer n’existe pas dans le stage runner. À reposer dans le stage final.

Transports pino en worker thread

pino-pretty (dev) et pino-opentelemetry-transport (POSTHOG_LOGS_ENABLED=true) tournent dans un worker thread qui charge son module depuis node_modules — absent des images standalone qui ne copient que dist/. Résultat : ModuleNotFound: thread-stream, crash.
En prod, garder POSTHOG_LOGS_ENABLED=false : pino écrit alors en JSON sur stdout, que Docker/Dokploy capturent déjà.

Collision de casse (macOS ↔ Linux)

macOS est insensible à la casse, Linux (donc Docker/Dokploy) sensible. Un import ./Experience qui résout un fichier experience.tsx en local casse au build Docker. Toujours faire matcher exactement la casse import ↔ fichier.

Checklist Dokploy

1

API

Toutes les vars en Environment (runtime). Aucune en build arg. NODE_ENV=production, POSTHOG_LOGS_ENABLED=false, valeurs sans guillemets.
2

Apps Vite

Les VITE_* en Build Arguments (pas runtime). Vérifier que chaque var a son ARG dans le Dockerfile de l’app.
3

Reproduire en local