Les variables d'environnement gardent les secrets hors du code source et permettent de modifier la configuration sans redéployer. Le fichier .env est devenu la méthode standard pour les gérer localement. Ce guide couvre les règles de syntaxe, la configuration des frameworks, la sécurité, les fichiers spécifiques à l'environnement, l'intégration Docker, les erreurs courantes et les alternatives en production.
Règles de syntaxe .env
Un fichier .env est un fichier texte brut avec une variable par ligne. Voici les règles que tout développeur doit connaître :
Syntaxe de base
Chaque ligne suit le modèle KEY=VALUE. Pas d'espaces autour du signe égal.
# .env
DATABASE_URL=postgres://localhost:5432/mydb
API_KEY=sk-1234567890abcdef
PORT=3000
DEBUG=trueRègles de guillemets
Les valeurs peuvent être sans guillemets, entre guillemets simples ou doubles. Le comportement diffère :
# Unquoted — trailing whitespace trimmed
APP_NAME=My Application
# Single quotes — literal, no interpolation
PASSWORD='p@$$w0rd#123'
# Double quotes — escape sequences + interpolation
GREETING="Hello\nWorld"
FULL_URL="${BASE_URL}/api/v1"- Sans guillemets : les espaces en fin de ligne sont supprimés, pas de séquences d'échappement.
- Guillemets simples : la valeur est prise littéralement, pas d'interpolation ni d'échappement.
- Guillemets doubles : supporte les séquences d'échappement (\n, \t) et l'interpolation de variables.
Valeurs multilignes
Utilisez des guillemets doubles et \n pour les sauts de ligne, ou des sauts de ligne réels entre guillemets doubles :
# Method 1: \n in double quotes
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIB...\n-----END RSA PRIVATE KEY-----"
# Method 2: actual newlines in double quotes
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----"Commentaires
Les lignes commençant par # sont des commentaires. Les commentaires en ligne fonctionnent uniquement avec les valeurs sans guillemets dans certains parseurs :
# This is a full-line comment
DATABASE_URL=postgres://localhost/mydb # inline comment (some parsers)
# Empty lines are ignored
API_KEY=abc123 # This may or may not work depending on the parserInterpolation de variables
Référencez d'autres variables avec la syntaxe ${VAR} (supporté par la plupart des parseurs dans les valeurs entre guillemets doubles) :
BASE_URL=https://api.example.com
API_V1=${BASE_URL}/v1
API_V2=${BASE_URL}/v2
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DATABASE_URL=postgres://${DB_HOST}:${DB_PORT}/${DB_NAME}Configuration des frameworks
Node.js (dotenv)
Le chargeur .env le plus populaire pour Node.js. Installation et configuration :
# Install
npm install dotenv
# --- app.js (CommonJS) ---
require('dotenv').config();
console.log(process.env.DATABASE_URL);
# --- app.ts (ES Modules) ---
import 'dotenv/config';
console.log(process.env.DATABASE_URL);
# --- Or load from CLI ---
node -r dotenv/config app.js
node -r dotenv/config app.js dotenv_config_path=.env.localNext.js, Vite et Create React App chargent automatiquement les fichiers .env — aucun package nécessaire.
Python (python-dotenv)
Charger .env dans les projets Python :
# Install
pip install python-dotenv
# --- app.py ---
from dotenv import load_dotenv
import os
load_dotenv() # loads .env from current directory
# load_dotenv('.env.local') # or specify a path
database_url = os.getenv('DATABASE_URL')
print(database_url)
# --- Django: manage.py or settings.py ---
from dotenv import load_dotenv
from pathlib import Path
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path)Go (godotenv)
Charger .env dans les projets Go :
// Install
// go get github.com/joho/godotenv
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
err := godotenv.Load() // loads .env
if err != nil {
log.Fatal("Error loading .env file")
}
dbURL := os.Getenv("DATABASE_URL")
fmt.Println(dbURL)
}PHP (vlucas/phpdotenv)
Utilisé par Laravel et la plupart des frameworks PHP :
// Install
// composer require vlucas/phpdotenv
<?php
require 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
// Access variables
$dbUrl = $_ENV['DATABASE_URL'];
// or
$dbUrl = getenv('DATABASE_URL');
// Required variables (throws exception if missing)
$dotenv->required(['DATABASE_URL', 'API_KEY']);Ruby (gem dotenv)
Utilisé par Rails et d'autres projets Ruby :
# Gemfile
gem 'dotenv-rails', groups: [:development, :test]
# Or for non-Rails Ruby:
gem 'dotenv'
# --- app.rb ---
require 'dotenv/load'
puts ENV['DATABASE_URL']
# --- Rails: .env is loaded automatically ---
# Access via ENV['DATABASE_URL'] anywhere in your appSécurité : ne jamais commiter les fichiers .env
Votre fichier .env contient des secrets (clés API, mots de passe de base de données, tokens). Le commiter dans le contrôle de version est l'erreur de sécurité n°1.
Patterns .gitignore
Ajoutez immédiatement ces patterns à votre fichier .gitignore :
# .gitignore
# Ignore all .env files
.env
.env.local
.env.*.local
.env.development
.env.production
# More aggressive pattern — ignore all .env variants
.env*
# But DO commit the example file
!.env.exampleUtiliser .env.example
Commitez un fichier .env.example avec des valeurs vides pour que les coéquipiers sachent quelles variables sont requises :
# .env.example — commit this file
# Copy to .env and fill in your values
DATABASE_URL=
API_KEY=
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
REDIS_URL=
JWT_SECRET=
# Optional
DEBUG=false
LOG_LEVEL=info.env déjà commité ?
Si vous avez accidentellement commité un fichier .env, retirez-le du suivi et changez tous les secrets :
# Step 1: Remove .env from Git tracking (keeps local file)
git rm --cached .env
# Step 2: Add to .gitignore
echo ".env" >> .gitignore
# Step 3: Commit the removal
git add .gitignore
git commit -m "Remove .env from tracking, add to .gitignore"
# Step 4: CRITICAL — Rotate ALL secrets in the .env file
# Every API key, password, and token that was exposed
# must be regenerated immediatelyFichiers spécifiques à l'environnement
La plupart des frameworks supportent plusieurs fichiers .env pour différents environnements. Comprendre l'ordre de chargement est crucial.
Ordre de chargement (Next.js / Vite / CRA)
Les fichiers sont chargés dans cet ordre de priorité (les fichiers suivants écrasent les précédents) :
# Loading priority (highest to lowest):
# 1. Shell environment variables (always win)
# 2. .env.{NODE_ENV}.local (e.g. .env.production.local)
# 3. .env.local (NOT loaded in test)
# 4. .env.{NODE_ENV} (e.g. .env.production)
# 5. .env (default fallback)
# Example for NODE_ENV=production:
# .env → loaded first (base defaults)
# .env.production → overrides .env
# .env.local → overrides .env.production
# .env.production.local → overrides everything above.env.local est toujours ignoré par git (ajoutez-le à .gitignore). Il n'est PAS chargé pendant les tests pour garder les tests déterministes.
Quel fichier pour quoi ?
| File | Purpose | Git |
|---|---|---|
| .env | Default values, non-secret config | Commit |
| .env.example | Template with empty values | Commit |
| .env.local | Local secrets & overrides | Ignore |
| .env.development | Dev-specific (shared) | Commit |
| .env.production | Production-specific (non-secret) | Commit |
| .env.test | Test environment config | Commit |
| .env.production.local | Production secrets (local only) | Ignore |
Intégration Docker et Docker Compose
Directive env_file
Docker Compose peut charger les fichiers .env directement dans les conteneurs :
# docker-compose.yml (or compose.yml)
services:
web:
image: node:20-alpine
env_file:
- .env # base defaults
- .env.production # production overrides
ports:
- "3000:3000"
db:
image: postgres:16
env_file:
- .env.db # separate file for DB secrets
volumes:
- pgdata:/var/lib/postgresql/dataenvironment vs env_file
Vous pouvez aussi définir les variables d'environnement en ligne. Voici la différence :
# Using env_file (loads from file)
services:
web:
env_file:
- .env
# Using environment (inline)
services:
web:
environment:
- NODE_ENV=production
- PORT=3000
- DATABASE_URL=${DATABASE_URL} # from shell or .env
# Using environment (mapping syntax)
services:
web:
environment:
NODE_ENV: production
PORT: 3000- env_file : charge depuis un fichier, garde compose.yml propre, facile à changer par environnement.
- environment : visible dans compose.yml, adapté aux valeurs non secrètes, supporte la substitution de variables.
.env pour les variables Docker Compose
Docker Compose lit automatiquement un fichier .env à la racine du projet pour la substitution de variables dans compose.yml :
# .env (in same directory as compose.yml)
POSTGRES_VERSION=16
NODE_VERSION=20
APP_PORT=3000
# compose.yml — uses .env for variable substitution
services:
web:
image: node:${NODE_VERSION}-alpine
ports:
- "${APP_PORT}:3000"
db:
image: postgres:${POSTGRES_VERSION}
environment:
POSTGRES_DB: myapp10 erreurs .env courantes et corrections
Voici les problèmes .env les plus fréquents rencontrés par les développeurs :
| # | Erreur | Cause | Correction |
|---|---|---|---|
| 1 | process.env.VAR est undefined | dotenv non chargé ou chargé après utilisation | Appelez dotenv.config() tout en haut de votre fichier d'entrée |
| 2 | Variables vides en production | Fichier .env non déployé ; dépendance au fichier plutôt qu'aux variables de la plateforme | Définissez les variables dans votre plateforme d'hébergement (Vercel, AWS, etc.) |
| 3 | Les valeurs .env contiennent des guillemets | Le parseur traite les guillemets comme des caractères littéraux | Vérifiez la documentation du parseur |
| 4 | Mauvais fichier .env chargé | Le répertoire de travail diffère du chemin attendu | Utilisez l'option path : dotenv.config({ path: ".env.local" }) |
| 5 | Valeur multiligne tronquée | Valeur non correctement entre guillemets doubles | Entourez les valeurs multilignes de guillemets doubles |
| 6 | Les caractères spéciaux cassent la valeur | $ ou # interprété comme interpolation/commentaire | Utilisez des guillemets simples ou échappez avec \ |
| 7 | Erreur d'encodage BOM | Éditeur Windows sauvegarde .env en UTF-8 BOM | Sauvegardez en UTF-8 sans BOM |
| 8 | Variables d'environnement Docker vides | Chemin env_file incorrect ou fichier hors du contexte de build | Vérifiez que le chemin est relatif à l'emplacement de compose.yml |
| 9 | Espaces autour de = cassent le parsing | KEY = VALUE au lieu de KEY=VALUE | Supprimez les espaces autour du signe égal |
| 10 | Variables indisponibles dans le navigateur (React/Next) | Préfixe requis manquant (NEXT_PUBLIC_ ou REACT_APP_) | Ajoutez le préfixe requis par le framework pour exposer au code côté client |
Alternatives en production
En production, les fichiers .env ne sont pas recommandés. Utilisez ces alternatives :
Variables d'environnement de la plateforme
Chaque plateforme d'hébergement majeure fournit une UI ou CLI pour définir les variables d'environnement :
# Vercel
vercel env add DATABASE_URL production
vercel env ls
# AWS (Parameter Store)
aws ssm put-parameter \
--name "/myapp/prod/DATABASE_URL" \
--value "postgres://..." \
--type SecureString
# Heroku
heroku config:set DATABASE_URL=postgres://...
heroku config
# Railway
railway variables set DATABASE_URL=postgres://...
# Fly.io
fly secrets set DATABASE_URL=postgres://...Docker Secrets
Pour Docker Swarm ou Compose, utilisez les secrets pour les données sensibles :
# compose.yml with Docker secrets
services:
web:
image: myapp:latest
secrets:
- db_password
- api_key
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt # for Compose
# external: true # for Swarm
api_key:
file: ./secrets/api_key.txt
# In your app, read from file:
# const secret = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();Gestionnaires de secrets (Vault, AWS Secrets Manager)
Pour les applications d'entreprise, utilisez un gestionnaire de secrets dédié :
# HashiCorp Vault
vault kv put secret/myapp/production \
DATABASE_URL="postgres://..." \
API_KEY="sk-..."
# Read in application
vault kv get -field=DATABASE_URL secret/myapp/production
# AWS Secrets Manager
aws secretsmanager create-secret \
--name "myapp/production/db" \
--secret-string '{"url":"postgres://...","password":"..."}'
# Read in Node.js with AWS SDK
import { SecretsManager } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManager({ region: 'us-east-1' });
const { SecretString } = await client.getSecretValue({
SecretId: 'myapp/production/db'
});
const secrets = JSON.parse(SecretString);Les gestionnaires de secrets fournissent la rotation, les logs d'audit, le contrôle d'accès et le chiffrement au repos — des fonctionnalités que les fichiers .env ne peuvent pas offrir.
Questions fréquentes
Dois-je commiter mon fichier .env dans Git ?
Ne commitez jamais les fichiers .env contenant des secrets dans le contrôle de version. Commitez plutôt un fichier .env.example avec des valeurs vides. Ajoutez les patterns .env* à votre .gitignore.
Quelle est la différence entre .env, .env.local et .env.production ?
.env contient les valeurs par défaut chargées dans tous les environnements. .env.local contient les surcharges locales non commitées. .env.production contient les valeurs spécifiques à la production chargées uniquement quand NODE_ENV=production.
Pourquoi process.env.MY_VAR est undefined dans Node.js ?
Causes les plus courantes : 1) Oubli d'appeler require("dotenv").config() en haut du fichier d'entrée, 2) Le fichier .env n'est pas à la racine, 3) Faute de frappe dans le nom de variable, 4) Avec ES modules, utilisez "import dotenv/config".
Comment utiliser les variables .env dans Docker Compose ?
Docker Compose lit automatiquement un fichier .env dans le même répertoire que compose.yml pour la substitution de variables ${VAR}. Pour passer des variables aux conteneurs, utilisez env_file ou environment.
Peut-on utiliser les fichiers .env en production ?
Ce n'est pas recommandé. En production, utilisez les variables d'environnement de la plateforme, Docker secrets ou un gestionnaire de secrets comme HashiCorp Vault ou AWS Secrets Manager.
Comment exposer les variables .env au navigateur dans React ou Next.js ?
Dans Next.js, préfixez avec NEXT_PUBLIC_. Dans Create React App, utilisez REACT_APP_. Dans Vite, utilisez VITE_. Seules les variables préfixées sont intégrées dans le bundle client.