backend / nodejs
Variables d'environnement et configuration
Explication
Ce que vous allez apprendre
- Séparer la configuration du code source avec des variables d'environnement
- Charger un fichier
.envnativement avec Node.js 20+, sans dépendance externe - Valider
process.envavec un schéma (Zod) pour échouer vite en cas de config incomplète - Protéger les secrets en excluant
.envde git et en documentant avec.env.example - Comprendre quand passer d'un simple fichier
.envà un gestionnaire de secrets dédié
Dans quel contexte ?
Une équipe déploie la même API sur trois environnements (développement local, préproduction, production), chacun avec sa propre base de données et ses propres clés secrètes. Un développeur commite accidentellement un fichier .env contenant une vraie clé JWT de production dans le dépôt git : cette leçon montre comment cette configuration doit être organisée pour qu'un tel incident soit structurellement impossible.
Le problème, d'abord
Une application ne se comporte pas de la même façon en développement et en production. Base de données locale et logs verbeux d'un côté, base distante, secrets réels et logs discrets de l'autre.
Coder ces différences "en dur" dans le code source poserait un vrai problème. Il faudrait modifier et redéployer le code à chaque changement d'environnement.
Les variables d'environnement résolvent exactement ça. Elles permettent d'injecter cette configuration de l'EXTÉRIEUR, sans jamais toucher au code source.
Une fois ce principe posé, un danger réel apparaît vite : les secrets dans git. Un mot de passe de base de données ou une clé JWT commité dans git reste dans l'HISTORIQUE du dépôt pour toujours, même supprimé plus tard.
Piège fréquent
Supprimer un fichier .env d'un commit ultérieur ne le retire PAS de l'historique git : n'importe qui peut encore le retrouver avec git log -p. Si un secret a été commité par erreur, la seule solution fiable est de le révoquer/régénérer immédiatement, pas de "juste" le supprimer.
C'est pourquoi le fichier .env doit systématiquement être dans .gitignore. Il est remplacé par un .env.example, qui documente les variables attendues SANS révéler de vraies valeurs.
Une fois les secrets protégés, il reste un autre risque à anticiper : la variable manquante découverte trop tard. Sans validation, une variable manquante ou mal formée peut passer inaperçue jusqu'à ce que le code essaie réellement de l'utiliser.
Et ce moment survient souvent au pire endroit possible : en pleine charge de production. La solution consiste à valider process.env avec un schéma dès le démarrage de l'application.
Ça permet de faire échouer le lancement IMMÉDIATEMENT et clairement. Plutôt que de laisser tourner un serveur dans un état de configuration incohérent, potentiellement dangereux.
Pour aller plus loin, sache qu'un simple fichier .env a ses limites en production à grande échelle. C'est un fichier texte en clair sur le disque, acceptable en développement mais risqué à grande échelle.
Des gestionnaires de secrets dédiés comme AWS Secrets Manager ou HashiCorp Vault ajoutent chiffrement, contrôle d'accès et audit. Un niveau de rigueur adapté aux environnements les plus sensibles.
| Solution | Convient pour | Limite |
|---|---|---|
Fichier .env | développement local, petits projets | texte en clair sur le disque |
| Variables injectées (Docker/K8s) | production, CI/CD | pas d'audit ni de rotation automatique |
| AWS Secrets Manager / Vault | environnements sensibles, conformité | complexité et coût d'infrastructure |
Le piège fréquent à connaître avant de pratiquer : centraliser la configuration dans un seul fichier plutôt que d'accéder à process.env.X un peu partout facilite les tests, mais l'oubli le plus courant reste de ne PAS valider la config au démarrage.
Commandes & code
Variables d'environnement et configuration
# .env — jamais commité (dans .gitignore)
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
JWT_ACCESS_SECRET=change-me-en-production
REDIS_URL=redis://localhost:6379// Node.js 20+ charge nativement les fichiers .env, sans dépendance externe
// package.json : "dev": "node --env-file=.env src/index.js"
console.log(process.env.PORT); // "3000"// config/env.js — valider et typer la config au démarrage avec Zod
import { z } from "zod";
const envSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.string().url(),
JWT_ACCESS_SECRET: z.string().min(32),
REDIS_URL: z.string().url(),
});
const parsed = envSchema.safeParse(process.env);
if (!parsed.success) {
console.error("Configuration invalide:", parsed.error.flatten().fieldErrors);
process.exit(1); // échouer vite plutôt que de démarrer dans un état incohérent
}
export const env = parsed.data;// config/index.js — configuration typée et centralisée par environnement
import { env } from "./env.js";
const configs = {
development: {
logLevel: "debug",
corsOrigins: ["http://localhost:3000"],
},
production: {
logLevel: "warn",
corsOrigins: ["https://monapp.com"],
},
test: {
logLevel: "silent",
corsOrigins: [],
},
};
export const config = {
port: env.PORT,
databaseUrl: env.DATABASE_URL,
...configs[env.NODE_ENV],
};// Secrets en production : préférer un gestionnaire de secrets à un fichier .env
// AWS Secrets Manager, HashiCorp Vault, ou variables injectées par la plateforme (Docker/K8s)
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
async function loadSecretsFromAWS() {
const client = new SecretsManagerClient({ region: "eu-west-1" });
const response = await client.send(
new GetSecretValueCommand({ SecretId: "prod/api/secrets" })
);
return JSON.parse(response.SecretString);
}# docker-compose.yml — injection de variables sans fichier .env commité
services:
api:
build: .
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
env_file:
- .env.production.local # présent uniquement sur le serveur, jamais dans gitRésumé
- Valider
process.envavec un schéma (Zod) fait échouer le démarrage immédiatement si la config est incomplète. - Ne jamais commiter de fichier
.envcontenant de vrais secrets — utiliser.env.examplecomme documentation. - En production, préférer un gestionnaire de secrets dédié (Vault, AWS Secrets Manager) à un simple fichier.
- Centraliser la config dérivée de l'environnement (
config/index.js) évite lesprocess.env.Xdispersés dans le code.
Exercices pratiques
Mission : une clé de production a fuité dans l'historique git
Objectif : Réagir correctement à un secret commité par erreur, puis mettre en place une validation stricte de la configuration au démarrage.
Contexte
Un développeur découvre que le fichier .env contenant JWT_ACCESS_SECRET=prod-k7x9... (la vraie clé de production) a été commité il y a trois semaines, puis "supprimé" dans un commit plus récent en pensant avoir réglé le problème. Par ailleurs, le serveur démarre actuellement sans jamais vérifier que DATABASE_URL ou JWT_ACCESS_SECRET sont bien définis : une variable manquante ne provoque une erreur que des heures plus tard, au moment précis où une requête tente de s'en servir, en pleine charge de production.