Quando sviluppiamo un'applicazione con Node.js, spesso abbiamo bisogno di gestire informazioni sensibili come password del database, chiavi API o porte del server. Scrivere questi dati direttamente nel codice è rischioso e poco flessibile. Per questo utilizziamo le variabili d'ambiente, che ci permettono di separare la configurazione dal codice.
In questa lezione vedremo come utilizzare le variabili d'ambiente in Node.js tramite il file .env e il pacchetto dotenv.
Le variabili d'ambiente offrono diversi vantaggi importanti per lo sviluppo di applicazioni:
Senza variabili d'ambiente, dovremmo scrivere direttamente nel codice informazioni come queste:
const mysql = require("mysql");
const con = mysql.createConnection({
host: "localhost",
user: "root",
password: "password_segreta_123",
database: "esempio"
});Se questo codice venisse condiviso o reso visibile, chiunque potrebbe vedere la password del database. Con le variabili d'ambiente, questi dati restano privati.
Un file .env è un file di testo che contiene le variabili d'ambiente della nostra applicazione. Si trova tipicamente nella cartella principale del progetto e presenta una struttura estremamente semplice: ogni riga definisce una coppia nel formato NOME_VARIABILE=valore.
Esempio di un file .env:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password_segreta_123
DB_NAME=esempio
PORT=3000Il file .env non va mai caricato su repository pubblici come GitHub. Per questa ragione, viene automaticamente aggiunto al file .gitignore (un argomento che approfondiremo più avanti).
Scrivere dati sensibili direttamente all'interno del codice sorgente comporta svariati rischi:
Le variabili d'ambiente risolvono efficacemente tutti questi problemi, mantenendo i dati sensibili separati dal codice.
Per poter utilizzare le variabili d'ambiente in un'applicazione Node.js, è necessario il pacchetto dotenv, il quale si occupa di caricare automaticamente le variabili dal file .env e renderle disponibili all'interno dell'applicazione.
Per prima cosa, dobbiamo installare dotenv all'interno della cartella del nostro progetto. Apriamo il terminale, navighiamo nella directory del progetto e installiamo il pacchetto tramite npm:
npm install dotenvCompletata l'installazione, il pacchetto sarà disponibile nel progetto e verrà automaticamente aggiunto al file package.json nella sezione dependencies.
Dopo aver installato dotenv, è necessario creare il file .env nella cartella principale del progetto (la stessa dove risiede package.json).
Creiamo un nuovo file chiamato .env (prestando attenzione a non inserirlo nella directory pubblica) e inseriamo al suo interno le nostre variabili d'ambiente:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=la_tua_password
DB_NAME=esempio
PORT=3000
API_KEY=chiave_api_segreta_123Ogni variabile è scritta su una riga separata, senza spazi prima o dopo il segno =. Per convenzione, i nomi delle variabili sono scritti in maiuscolo con underscore (_) per separare le parole.
Per rendere disponibili le variabili del file .env nella nostra applicazione, dobbiamo caricare dotenv all'inizio del file JavaScript principale:
require("dotenv").config();
console.log(process.env.DB_HOST); // localhost
console.log(process.env.PORT); // 3000L'istruzione require("dotenv").config() legge il file .env e carica tutte le variabili nell'oggetto process.env. Da questo momento, possiamo accedere a qualsiasi variabile usando process.env.NOME_VARIABILE.
È importante chiamare require("dotenv").config() all'inizio del file, prima di utilizzare qualsiasi variabile d'ambiente, altrimenti le variabili non saranno ancora disponibili.
Una volta caricato dotenv, possiamo accedere alle variabili d'ambiente tramite l'oggetto process.env.
Per leggere una variabile d'ambiente, utilizziamo process.env seguito dal nome della variabile:
require("dotenv").config();
const host = process.env.DB_HOST;
const porta = process.env.PORT;
console.log(`Server in esecuzione su ${host}:${porta}`);Nell'esempio leggiamo le variabili DB_HOST e PORT dal file .env e le utilizziamo nel nostro codice. Se le variabili non esistono nel file .env, process.env.NOME_VARIABILE restituirà undefined.
Un caso d'uso molto comune è utilizzare le variabili d'ambiente per le credenziali del database MySQL, che abbiamo visto nella lezione dedicata:
require("dotenv").config();
const mysql = require("mysql");
const con = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
con.connect(function (err) {
if (err) throw err;
console.log("Connesso al database!");
});Possiamo eseguire il codice Node.js se abbiamo configurato il file .env in questo modo:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=la_tua_password
DB_NAME=esempioIl codice si connetterà al database utilizzando questi valori.
Per utilizzare correttamente le variabili d'ambiente, è cruciale seguire tutte le accortezze necessarie, perché stiamo utilizzando credenziali che devono rimanere protette.
Il file .env contiene informazioni sensibili che non devono mai essere caricate su repository pubblici come GitHub. Per prevenire ciò (se in futuro abbiamo intenzione di pubblicare o condividere la nostra applicazione Node.js), dobbiamo aggiungere .env al file .gitignore.
Creiamo o modifichiamo il file .gitignore nella cartella principale del progetto e includiamo le seguenti righe:
.env
node_modules/In questo modo, Git ignorerà completamente il file .env e non lo includerà nei commit. Aggiungiamo anche node_modules/ per evitare di caricare tutti i pacchetti installati.
Al posto del file .env, è buona pratica creare un file .env.example contenente la struttura delle variabili ma privo dei valori reali:
DB_HOST=
DB_USER=
DB_PASSWORD=
DB_NAME=
PORT=
API_KEY=Questo file può essere caricato su GitHub per comunicare agli altri sviluppatori quali variabili sono necessarie, senza però rivelare i valori sensibili.
Spesso un'applicazione deve operare in ambienti diversi: sviluppo locale, test e produzione. Ogni ambiente richiede configurazioni specifiche (ad esempio, database o porte differenti).
Una strategia comune prevede l'utilizzo di file .env distinti per ciascun ambiente:
.env.development per lo sviluppo locale..env.test per i test..env.production per la produzione.Possiamo caricare il file corretto specificando il percorso nella chiamata a dotenv.config():
const dotenv = require("dotenv");
if (process.env.NODE_ENV === "production") {
dotenv.config({ path: ".env.production" });
} else if (process.env.NODE_ENV === "test") {
dotenv.config({ path: ".env.test" });
} else {
dotenv.config({ path: ".env.development" });
}In questo esempio, il codice carica il file .env appropriato basandosi sulla variabile NODE_ENV, che identifica l'ambiente corrente.
Un'altra buona pratica è fornire valori predefiniti per le variabili che potrebbero non essere definite:
const PORT = process.env.PORT || 3000;
const DB_HOST = process.env.DB_HOST || "localhost";In questo modo, se una variabile non è definita nel file .env, l'applicazione userà un valore predefinito. Questo evita errori durante l'esecuzione.