Valider tes variables d’environnement avec Zod et TypeScript
Évite les crashs prod : valide tes variables d’environnement au boot avec Zod. Autocomplétion TypeScript et secrets protégés dans ton projet React Router 7.
Pourquoi valider tes variables d’environnement ?
Une variable manquante ou mal nommée bloque tout le déploiement... Sans validation, l’erreur n’apparaît qu’en production.
Avec Zod tu :
- vérifies la présence et le format de chaque clé dès le boot ;
- profites de l’autocomplétion TypeScript (
process.env.DATABASE_URL) ; - évites de propager un secret côté client par mégarde.
Installer Zod côté serveur
1npm add zod
Zod est déjà présent dans le projet (Conform), mais on l’installe ici pour les lecteurs qui partent d’un repo vierge.
Créer le schéma serverEnvSchema
1import z from "zod"23const minLength = 4 // longueur mini partagée45const serverEnvSchema = z.object({6DATABASE_URL: z7.string({ message: "DATABASE_URL is missing" })8.min(minLength, { message: "DATABASE_URL is too short" }),910FRONTEND_URL: z11.string({ message: "FRONTEND_URL is missing" })12.min(minLength, { message: "FRONTEND_URL is too short" }),1314AWS_ACCESS_KEY_ID: z.string().min(minLength),15AWS_SECRET_ACCESS_KEY: z.string().min(minLength),16AWS_REGION: z.string().min(minLength),17AWS_S3_BUCKET_NAME: z.string().min(minLength),1819BETTER_AUTH_SECRET: z.string().min(minLength),20BETTER_AUTH_URL: z.string().min(minLength),2122STRIPE_PUBLISHABLE_KEY: z.string().min(minLength),23STRIPE_SECRET_KEY: z.string().min(minLength),24STRIPE_WEBHOOK_SECRET: z.string().min(minLength),2526RESEND_API_KEY: z.string().min(minLength),27RESEND_FROM_EMAIL: z.string().min(minLength),28})
Explications :
minLengthcentralise la contrainte minimale (4 caractères ici).- Chaque clé reçoit un message clair en cas d’erreur.
- On liste seulement les variables réellement utilisées dans le projet ; pas de clé fantôme.
Parser et exposer l’objet typé
1export const serverEnv = serverEnvSchema.parse(process.env)
parse() :
- déclenche un crash explicite si une variable manque ;
- renvoie un objet typé pour le reste de l’app (intellisense VS Code).
Étendre le type ProcessEnv (auto-complétion)
1declare global {2namespace NodeJS {3interface ProcessEnv extends z.infer<typeof serverEnvSchema> {}4}5}
Désormais :
1process.env.AWS_REGION // ✔ auto-complété, erreur de compile si renommé
Utiliser les variables dans le loader root
1import { serverEnv } from "~/server/env.server"23export async function loader({ request }: Route.LoaderArgs) {4const { FRONTEND_URL } = serverEnv // ^? typé string5/* … */6return data({7/* … */,8env: { FRONTEND_URL }, // seules les clés publiques9})10}
Idée : ne transmettre au client que ce qui est nécessaire (FRONTEND_URL ici).
Créer un hook côté client
1export function useEnv() {2return useRouteLoaderData<typeof loader>("root")?.env ?? null3}
Le composant peut appeler :
1const env = useEnv()2env && console.log(env.FRONTEND_URL)
Pas de fuite : les secrets (SMTP, Stripe) restent côté serveur.
Avantages immédiats
| Problème avant Zod | Avec le schéma Zod |
|---|---|
| Variable oubliée → crash prod tardif | Crash instantané, message clair |
process.env.AWSS_SECRET (typo) passe | Erreur de compilation TypeScript |
| Secrets exposés par erreur | On choisit précisément env: {} |
Aller plus loin
- Sépare les variables test/staging/prod dans plusieurs fichiers
.envet charge-les via dotenv. - Vérifie qu’aucun secret ne fuite côté client avec les DevTools.
la validation est reprise dans le module déploiement pour éviter un build cassé – voir /formations/react-router-7/deploiement-dune-application-react-router-7/configurer-les-github-actions.
Comprendre les concepts fondamentaux
Quelle est la principale différence entre les composants client et serveur dans React ?
Optimisation des performances
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Architecture des données
Quel hook permet de gérer les effets de bord dans un composant React ?