.env Les fichiers de configuration sont de plus en plus utilisés pour configurer une application en stockant en toute sécurité les paramètres de configuration, les variables d'environnement et les informations sensibles. Cette norme non contraignante offre de nombreux avantages, dont la plupart sont pleinement exploités sur Upsun Cloud. Cependant, .env ces fichiers doivent aussi être utilisés correctement ; une mauvaise utilisation, comme pour tout, peut être pire que de ne pas les utiliser du tout.
Pour comprendre comment utiliser au mieux les .env ces fichiers, il faut d’abord comprendre ce qu’on entend par « environnement ».
Quel que soit le langage dans lequel elle est écrite, ton application est en fin de compte un tas de code. Ce tas de code est statique et ne change pas d’un moment à l’autre ni d’un endroit à l’autre où il s’exécute.
Mais quand elle s’exécute, elle va tenir compte d’autres « éléments ». Ces éléments peuvent être une base de données, un serveur de cache, un système de fichiers, une passerelle d’authentification à distance ou mille autres choses encore. Ces autres « éléments » constituent le contexte dans lequel l’application s’exécute. Ou, en d’autres termes, son environnement.
Cet environnement peut être variable. Ton application peut avoir besoin d’un serveur PostgreSQL, mais le serveur PostgreSQL auquel elle se connecte, ainsi que les données qu’il contient à un moment donné, font tous partie de l’environnement et peuvent changer indépendamment de ton code. Tu veux que ton application communique avec une passerelle de paiement, mais les identifiants qu’elle utilise peuvent varier en fonction du contexte dans lequel tu l’exécutes. (Intégrer les clés API de paiement de production dans ton application, puis l’envoyer en test, ça finit souvent mal. Crois-moi sur ce coup-là…)
Quand tu développes une application, c’est important de bien séparer « ce qui est identique dans tous les environnements » et « ce qui change dans chaque environnement ». Le premier, c’est ton code. Le second, c’est la configuration de ton environnement.
Les systèmes d’exploitation de type Unix disposent depuis des décennies d’un mécanisme permettant de gérer cette configuration spécifique à chaque environnement : les variables d’environnement. Les variables d’environnement sont des chaînes de caractères globales au système que n’importe quelle application peut lire à tout moment et utiliser pour décider quel code exécuter.
Ce n’est bien sûr pas la seule façon dont les applications peuvent modifier leur comportement. La plupart des applications disposent d’une sorte de « fichier de configuration », qui contient d’autres paramètres pouvant faire varier le comportement de l’application. Il peut s’agir de fichiers exécutables (PHP, JavaScript, Python, etc.) ou de fichiers non exécutables (YAML, XML, ini, JSON, TOML, etc.), et les détails varient autant que les applications elles-mêmes.
La distinction importante, c’est que certains de ces paramètres de configuration doivent varier en fonction de l’installation de l’application, tandis que d’autres varient en fonction de l’environnement. N’oublie pas qu’une application donnée peut être exécutée en plusieurs instances à des fins de test.
Par exemple, si tu développes une application que les utilisateurs peuvent installer et configurer eux-mêmes, le « nom de l’entreprise » auquel l’application est destinée variera en fonction de l’utilisateur qui l’exécute. Mais la base de données à laquelle elle se connecte variera pour chaque instance de l’application que cet utilisateur exécute. Pense à la production, aux tests, à un ordinateur portable local, etc. Toutes ces instances devraient avoir le même nom d’entreprise, mais des identifiants de base de données différents.
C’est la première étape importante : séparer la configuration propre à chaque installation (nom de l’entreprise) de celle propre à chaque environnement (base de données). Si tu mets ces éléments dans le même fichier, il devient beaucoup plus difficile de les adapter à chaque environnement sans modifier en même temps la configuration propre à chaque installation.
Un fichier de configuration exécutable comporte parfois une option « porte dérobée » permettant de faire varier l’environnement. Selon la façon dont le fichier est écrit, il peut être possible de le modifier manuellement pour qu’il lise certaines valeurs provenant d’ailleurs : un fichier d’inclusion supplémentaire, des variables d’environnement, etc. Mais ça reste quand même un piratage. Tu veux pouvoir mettre la configuration cohérente dans Git, pour que ses modifications soient répercutées sur toutes les instances, mais pas la configuration spécifique à l’environnement.
Et c’est là que les variables d’environnement entrent en jeu.
L’endroit idéal pour stocker la configuration spécifique à l’environnement, ce sont les variables d’environnement. Les mécanismes pour les définir sont bien établis. Les API pour les lire sont universelles. Même si deux applications différentes n’utilisent pas forcément le même nom de variable, il existe plein de façons simples de définir une variable d’environnement en fonction d’une autre.
Pour la production et les tests, le meilleur moyen de gérer les paramètres spécifiques à l'environnement reste donc les variables d'environnement. Soit tu conçois ton application pour qu’elle les lise directement, soit tu la conçois avec un fichier de configuration exécutable modifiable par l’utilisateur, qui peut être adapté pour lire les valeurs de l’environnement plutôt que de les coder en dur. Comme ça, quand tu déplaces l’application de la production vers un environnement de préproduction, puis vers un autre environnement de préproduction, ou encore vers un environnement spécifique à une branche, il te suffit de mettre à jour les variables d’environnement pour ces nouveaux environnements et l’application continuera de tourner sans problème.
Le bémol de cette approche, cependant, concerne le développement local. Il y a fort à parier que tu ne souhaites pas définir une variable globale sur l’ensemble de ton ordinateur juste pour indiquer à la version de développement de ton application quelles fausses informations d’identification utiliser ou où se trouve ta base de données de test. Même si tu utilises un environnement conteneurisé en local, tu ne voudras peut-être pas te prendre la tête avec les variables d’environnement directement.
C’est là que le .env fichier entre en jeu. .env est un standard de facto pour un fichier de type « ini » contenant de fausses variables d’environnement. Une application qui prend en charge les .env fichiers va, au démarrage, parcourir chaque ligne de ce fichier et lire les key=value paires. Pour chacune d’elles, elle appliquera la règle suivante : « SI une variable d’environnement portant ce nom n’existe pas encore, définis-la en fonction de ce fichier. » Cela définira la variable uniquement dans le cadre du processus de ton application, sans affecter les autres processus de l’ordinateur. Ensuite, le reste de ton application peut continuer et lire les données de l’environnement comme elle le ferait n’importe où ailleurs, sans se rendre compte de ce petit tour de passe-passe. (N’écris pas ce code toi-même. Il existe .env des bibliothèques de support dans tous les langages qui font exactement la même chose. Utilise-en une.)
C’est ça, et rien d’autre, le but des .env fichiers : des valeurs qui changent selon l’environnement, et qui ne font donc pas partie de ton code. Ce qui nous amène à la chose la plus importante à retenir à propos des .env fichiers : ils n’ont pas leur place dans Git. Tout ce qui se trouve dans Git est censé être identique dans tous les environnements, par conception, ce qui est exactement le contraire de ce à quoi servent les variables d’environnement et les .env fichiers.
Les valeurs qui ne changent pas d’un environnement à l’autre n’ont pas non plus leur place dans le .env fichier. Le nom du site, l’adresse e-mail de l’administrateur, etc., doivent se trouver soit dans un fichier de configuration en lecture seule validé dans Git, soit dans la base de données, selon que tu souhaites ou non que ces valeurs de configuration puissent être modifiées par l’utilisateur final. (Les deux options sont valables, à condition que ce soit un choix délibéré.) Mais ces valeurs n’ont pas leur place dans le .env fichier, car elles ne sont pas spécifiques à un environnement.
Une exception à cette règle s’applique aux modèles de configuration propres au framework, comme .env.example. Les environnements front-end modernes utilisent souvent ces fichiers modèles pour définir les clés non sensibles dont ton application a besoin. Même si le suivi de ces modèles structurels dans Git est une pratique courante pour faciliter l’intégration des membres de l’équipe, les fichiers .env locaux contenant de véritables secrets doivent rester strictement ignorés.
Parfois, tu peux vouloir adapter le code lui-même en fonction de l’environnement. En général, ça ne concerne pas le code source, mais le processus de compilation. Dans un langage compilé (C, Rust, Go, Java, etc.), tu peux vouloir conserver les symboles de débogage dans le code compilé en développement, mais pas en production. Même dans les langages interprétés (PHP, JavaScript, Python, etc.), tu peux vouloir compiler ton CSS ou ton JavaScript agrégé différemment, en supprimant les espaces blancs uniquement en production pour faciliter le débogage, par exemple.
Ça pose un problème sur Upsun Cloud, car, de par sa conception, l’étape de compilation s’exécute indépendamment de toute valeur spécifique à l’environnement. En effet, le résultat de la compilation peut être réutilisé dans un autre environnement, comme la production. Plus précisément, dans le cas d’une fusion rapide vers la production, on n’a pas besoin de recompiler ton application. La version compilée à partir d’une branche est réutilisée, ce qui signifie que ce que tu testais dans une branche correspond exactement, sur le disque, à ce qui est déployé en production. C’est la seule façon de minimiser les erreurs du type « ça marche sur ma branche » et ça fait partie intégrante du concept même du déploiement conteneurisé.
Mais que faire si tu veux « développer » sur une branche ? C’est là que .env convention de nommage des fichiers prend toute son importance. Ne considère pas les environnements hors production comme des environnements de développement. Le développement, c’est là où tu écris du code, c’est-à-dire sur ton ordinateur local. Sur ton ordinateur local, tu peux définir toutes les variables d’environnement (ou .env fichiers) que tu veux. Au lieu de considérer chaque branche comme un environnement de développement, considère-la plutôt comme un environnement de préproduction. La préproduction doit être aussi proche que possible de la production, y compris au niveau des modes de compilation.
Vu sous cet angle, ça n’a aucun sens que le mode de compilation varie en fonction de l’environnement, car c’est justement là que les « heisenbugs » risquent d’apparaître. Tu ne veux pas de heisenbugs. (Fais-moi confiance là-dessus.) Le « mode débogage » doit se dérouler là où tu débogues et écris ton code, c’est-à-dire dans ton environnement local.
C’est le seul endroit où tu peux, et où tu devrais, utiliser un .env fichier.
Donc, pour résumer :
.env Les fichiers constituent une variable d’environnement de substitution réservée au développement local, mais ne doivent jamais être validés dans Git.NEXT_PUBLIC_ ou VITE_) déterminent la visibilit é des variables. Assure-toi de limiter les identifiants sensibles à des variables réservées au backend pour empêcher les outils de build d’intégrer accidentellement des secrets dans le code public côté client.