File .env spiegati: parsing, conversione JSON e config
Un file .env è un elenco in testo semplice di coppie KEY=VALUE che tiene configurazione e segreti fuori dal codice sorgente. È il formato che Node, Vite, Next.js, Python, Ruby e Docker Compose caricano nell’ambiente del processo. Se stai cercando env to json, di solito vuoi una di due cose: trasformare un .env in JSON strutturato per i tuoi strumenti, oppure capire le regole abbastanza bene da farlo in sicurezza.
Tre punti mandano spesso fuori strada, quindi chiariamoli subito:
- Un file
.envè piatto. Non esiste annidamento. Ogni chiave sta al livello superiore. - Ogni valore è una stringa. dotenv non converte mai i tipi.
PORT=8080viene caricato come"8080", non come8080. - La grammatica è informale. Non esiste una specifica formale, quindi i loader non vanno d’accordo sui casi limite — virgolette, commenti, escape.
Questa guida copre le regole di parsing di dotenv, la mappatura .env↔JSON (e perché conviene convertire in un verso o nell’altro), una matrice decisionale su quando usare .env invece di JSON e come validare la configurazione prima che vada in produzione. Tutto quello descritto qui gira nel Convertitore ENV in JSON interamente nel browser, così anche un .env pieno di credenziali reali non lascia mai la pagina.
Cos’è un file .env?
Il file .env è lo standard di fatto per la configurazione dell’ambiente. La libreria dotenv (e le sue versioni per quasi ogni linguaggio) legge il file e inietta ogni coppia nel processo in esecuzione. La tua app legge poi process.env.DATABASE_URL invece di scrivere a codice fisso la stringa di connessione. Poiché il file contiene password di database, chiavi API, segreti OAuth e token di accesso, viene quasi sempre escluso da git e trattato come sensibile.
Anatomia di una riga
Ogni riga significativa è una coppia KEY=VALUE, divisa sul primo segno =. Le righe di commento e quelle vuote vengono saltate e un eventuale prefisso export viene rimosso:
# Database — questa intera riga è un commento
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
DATABASE_POOL_SIZE=10
# La riga vuota qui sopra viene ignorata
export DEPLOY_ENV=production # il prefisso `export` viene rimosso
JWT_SECRET="super secret value"
La chiave è tutto ciò che precede il primo =, ripulito dagli spazi circostanti. Il prefisso export esiste perché il file possa essere passato direttamente con source in una shell; i loader dotenv lo rimuovono automaticamente. Dividere sul primo = conta perché valori come DATABASE_URL spesso contengono propri caratteri = nelle query string.
Perché la config vive nell’ambiente
Il ragionamento viene dalla Twelve-Factor App, che dice di conservare la config nell’ambiente. La config cambia a ogni deploy (dev, staging, produzione), mentre il codice resta lo stesso. Tenerla nell’ambiente significa che cambi l’host di un database senza modificare o ridistribuire il sorgente, e la stessa build gira ovunque.
Un fraintendimento frequente: si cita “la config mai in un file” e si conclude che .env sia vietato. La regola vera è più ristretta. La config non dovrebbe essere un file commesso dentro l’app, mescolato al codice e tracciato nel controllo di versione. Un .env locale, escluso da git, per lo sviluppo va benissimo ed è la prassi. Quello che eviti è spedire in produzione un .env reale con i segreti incorporati.
Regole di parsing di .env (i casi limite su cui gli strumenti non concordano)
Poiché non c’è una specifica formale per parse a .env file, ogni loader prende le proprie decisioni ai bordi. Le regole qui sotto sono le convenzioni dotenv più diffuse: quelle che il convertitore implementa e su cui la maggior parte dei runtime concorda.
Virgolette ed escape
Il modo in cui un valore viene racchiuso tra virgolette cambia tutto:
- Le virgolette doppie elaborano le sequenze di escape.
\ndiventa un a capo,\tun tab,\run ritorno a capo,\\un backslash e\"una virgoletta doppia letterale. Un valore tra virgolette doppie può anche estendersi su più righe fino alla virgoletta di chiusura: è così che le chiavi private PEM entrano in un.env. - Le virgolette singole sono letterali. Nessun trattamento degli escape, esattamente come nella shell.
'no \n escapes here'mantiene il backslash e lanalla lettera. - I valori senza virgolette arrivano fino alla fine della riga, con lo spazio finale rimosso. Un
#in linea (uno spazio seguito da un cancelletto) inizia un commento che viene tolto.
Quest’ultima regola colpisce chi usa i colori esadecimali. COLOR=#ff0000 perde tutto ciò che segue il #. Mettilo tra virgolette, COLOR="#ff0000", e il valore sopravvive.
Tutto è una stringa
Questo è il fatto più importante in assoluto sul dotenv format. PORT=8080 non viene caricato come il numero 8080. Viene caricato come la stringa "8080", perché i valori di process.env sono sempre stringhe a runtime. dotenv non converte mai i tipi.
Questo provoca bug reali. if (process.env.DEBUG) è truthy anche quando DEBUG=false, perché "false" è una stringa non vuota. I confronti numerici falliscono in silenzio perché "8080" non è 8080. Qualsiasi funzionalità “deduci i tipi” (incluso l’interruttore nel convertitore) è uno strato di comodità aggiunto sopra dotenv, non parte dello standard. Usalo sapendo che il JSON differirà poi da ciò che la tua app riceve davvero.
Chiavi duplicate, valori multiriga e interpolazione
Quando la stessa chiave compare due volte, vince l’ultima occorrenza. Il valore precedente viene scartato in silenzio. È una trappola di configurazione frequente: un duplicato vagante in fondo a un file lungo oscura silenziosamente il valore che intendevi usare. Un buon convertitore segnala i duplicati con un avviso invece di inghiottirli.
I valori multiriga funzionano solo dentro le virgolette doppie, avvolgendosi su più righe fino alla " di chiusura. E l’interpolazione ${VAR} (il riferimento a una variabile da un’altra) esiste in alcuni loader ma non è universale. Non farci affidamento tra runtime diversi; un file che interpola senza problemi in uno stack può caricare la stringa letterale ${VAR} in un altro.
Regole di parsing in breve
| Riga in input | Valore analizzato | Regola |
|---|---|---|
PORT=8080 | "8080" | Senza virgolette, mantenuto come stringa (nessuna conversione di tipo) |
APP_NAME=My App # title | "My App" | Senza virgolette: commento # in linea rimosso, spazio finale tolto |
GREETING="Hello,\nWorld" | Hello,⏎World | Le virgolette doppie elaborano \n come un a capo reale |
LITERAL='no \n escapes' | no \n escapes | Le virgolette singole sono letterali, nessun trattamento degli escape |
COLOR=#ff0000 | "" | Il # senza virgolette inizia un commento: il valore va perso; mettilo tra virgolette |
export AWS_REGION=us-east-1 | us-east-1 | Prefisso export rimosso |
EMPTY= | "" | Un valore vuoto è una stringa vuota valida |
.env vs JSON config: quando usare l’uno o l’altro
La risposta onesta non è “JSON è meglio”. Risolvono problemi diversi. Un file .env è piatto, solo stringhe, ammette i commenti e si definisce per ambiente: è fatto per i segreti e per le override al momento del deploy. JSON è annidato, tipizzato e strutturato, ma non ha commenti ed è facile da committare per sbaglio. Scegliere tra i due è la vera decisione env vs json config.
Cosa .env non può fare
Un .env non può annidare, non può contenere array e non può portare tipi reali. È un elenco piatto di stringhe. Se la tua config è naturalmente raggruppata, la appiattisci con una convenzione a prefisso invece di annidarla: DB_HOST e DB_PORT al posto di un oggetto db. Le chiavi restano piatte; ricomponi il raggruppamento nel codice.
In cosa JSON è migliore
JSON vince quando la struttura è il punto: oggetti annidati, array e numeri, booleani e null reali. È il formato che validi contro uno schema e quello da cui generi i tipi. Se ti serve una gerarchia che un file piatto non può esprimere, JSON (o YAML, di cui parliamo più sotto) è lo strumento giusto.
Matrice decisionale
| Esigenza | .env | JSON | Perché |
|---|---|---|---|
| Segreti / credenziali | ✅ | ⚠️ | .env è escluso da git per convenzione; la config JSON è facile da commettere per sbaglio |
| Override per ambiente | ✅ | ⚠️ | Un .env per ambiente è lo schema di deploy standard |
| Struttura annidata | ❌ | ✅ | .env è piatto; JSON annida nativamente |
| Valori tipizzati (numero/bool/null) | ❌ | ✅ | I valori .env sono sempre stringhe; JSON ha tipi reali |
| Commenti in linea | ✅ | ❌ | .env supporta #; JSON non ha sintassi per i commenti |
| Validazione con schema | ⚠️ | ✅ | Valida dopo aver convertito .env→JSON; JSON si valida direttamente |
Convertire .env in JSON e viceversa
Convertire in entrambi i versi è meccanico una volta che conosci le regole. La mappatura è 1:1 al livello superiore (ogni riga KEY=VALUE è una proprietà JSON) e l’unica sottigliezza riguarda i tipi e l’annidamento.
.env → JSON
Ogni coppia KEY=VALUE diventa una proprietà JSON. Per impostazione predefinita ogni valore è una stringa, fedele a ciò che dotenv carica a runtime; un interruttore opzionale di inferenza dei tipi promuove numeri, booleani e null non racchiusi tra virgolette. Il risultato è un oggetto piatto. Lo fai per dare la config in pasto a strumenti che leggono solo JSON, per importare in blocco in un gestore di segreti, per validare contro uno schema o semplicemente per leggere un .env sterminato come dati strutturati. Il Convertitore ENV in JSON fa esattamente questo nel browser, con un avviso quando individua chiavi duplicate.
JSON → .env
Il verso inverso accetta solo un oggetto: un array al livello superiore o uno scalare nudo non ha nomi di chiave da mappare a variabili. Numeri e booleani vengono scritti nudi (PORT=8080), null diventa un KEY= vuoto e qualsiasi stringa che contiene uno spazio, #, a capo o virgolette viene automaticamente racchiusa tra virgolette doppie ed escapata così da fare un round-trip sicuro. Oggetti e array annidati non possono vivere in un file piatto, quindi ciascuno viene serializzato in una stringa JSON e segnalato con un avviso. Interruttori opzionali normalizzano le chiavi in UPPER_SNAKE_CASE e aggiungono un prefisso export. Il Convertitore JSON in ENV gestisce tutto questo.
Sicurezza del round-trip e l’avvertenza sull’annidamento
L’auto-quoting esiste perché un valore sopravviva al ciclo .env → JSON → .env immutato. Il round-trip qui sotto è codice eseguibile, in linea con il comportamento dei convertitori; nota che PORT resta una stringa per tutto il ciclo, esattamente come dotenv lo caricherebbe:
import { parse } from 'dotenv';
// 1. Parti da un file .env come testo
const envText = `DATABASE_URL=postgres://user:pass@localhost:5432/mydb
PORT=8080
GREETING="Hello, World"
NOTE="value with # hash"`;
// 2. .env -> JSON (dotenv.parse restituisce solo valori stringa)
const config = parse(envText);
console.log(JSON.stringify(config, null, 2));
// {
// "DATABASE_URL": "postgres://user:pass@localhost:5432/mydb",
// "PORT": "8080",
// "GREETING": "Hello, World",
// "NOTE": "value with # hash"
// }
// 3. JSON -> .env (metti tra virgolette solo le stringhe che ne hanno bisogno)
const needsQuotes = (s) => /[\s#"'\n]/.test(s);
const env = Object.entries(config)
.map(([key, value]) =>
needsQuotes(value) ? `${key}=${JSON.stringify(value)}` : `${key}=${value}`
)
.join('\n');
console.log(env);
// DATABASE_URL=postgres://user:pass@localhost:5432/mydb
// PORT=8080
// GREETING="Hello, World"
// NOTE="value with # hash"
L’insidia è l’annidamento. Il round-trip è senza perdite per la config piatta, ma una struttura profondamente annidata può passare per .env solo come stringhe JSON opache, illeggibili per qualsiasi app che si aspetta indietro la struttura. Se la tua config è davvero gerarchica, ricorri a YAML. Il convertitore Convertitore YAML in JSON e Il Problema Norway di YAML coprono quel percorso e i suoi spigoli.
Validare la configurazione dell’ambiente
Una variabile di config mancante o malformata non dovrebbe emergere come un undefined is not a function alle 3 di notte in produzione. L’approccio Twelve-Factor è fallire in fretta: controlla la config prima del deploy invece che dopo. Convertire .env in JSON lo rende pratico, perché JSON ha strumenti di validazione maturi che le variabili d’ambiente grezze non hanno.
Validare con uno schema in CI
Converti .env → JSON, poi valida il JSON contro uno schema che dichiara le chiavi obbligatorie, gli enum ammessi e i formati dei valori. Un ambiente mal configurato (un DATABASE_URL mancante, un LOG_LEVEL non valido, una porta che non è un numero) fa fallire il controllo in CI invece del deploy. La Validazione JSON Schema spiega passo passo come scrivere lo schema, e il Validatore JSON Schema lo esegue nel browser.
Config tipizzata
Oltre ai controlli di presenza, puoi derivare un oggetto di config tipizzato così che process.env.PORT non sia una stringa non tipizzata sparsa per tutto il codice. Valida e converti i tipi all’avvio con una libreria di schema a runtime come Zod, oppure genera un’interfaccia TypeScript dal JSON e leggi la config attraverso quella. La Da JSON a TypeScript e il Convertitore da JSON a TypeScript coprono il passo di generazione. Formatta o controlla prima il JSON con il Formattatore JSON così che una sorpresa strutturale emerga presto.
Igiene dei segreti: gestire un .env in sicurezza
Un .env è, di fatto, un elenco di credenziali. Trattalo come tale.
Non committare mai .env. Aggiungilo a .gitignore. Committa un .env.example che elenca ogni chiave con valori vuoti o segnaposto, per esempio DATABASE_URL= invece della stringa di connessione reale. Quel file è il contratto del team: documenta quali variabili serve un nuovo clone senza farne trapelare nessuna.
.env è per locale e dev; la produzione usa un gestore di segreti. Strumenti come Vault, Doppler e AWS Secrets Manager iniettano i segreti nell’ambiente al momento del deploy. Non spedire un .env reale con segreti vivi su un host di produzione; recuperali piuttosto dal gestore, così che un file trapelato o un container mal configurato non consegni le tue chiavi.
Converti i segreti solo in uno strumento che gira nel browser. Incollare un .env reale in un convertitore lato server manda le tue credenziali in rete verso la macchina di qualcun altro. Entrambi i convertitori qui girano interamente nel tuo browser: apri la scheda Network nei DevTools e verifica che incollare scateni zero richieste. È questa la differenza che rende sicuro convertire un .env di produzione anziché un campione ripulito.
FAQ
Come converto un file .env in JSON?
Incolla il file nel Convertitore ENV in JSON e viene analizzato in JSON all’istante nel tuo browser. Ogni riga KEY=VALUE diventa una proprietà. I valori sono stringhe per impostazione predefinita (in linea con dotenv); attiva l’inferenza dei tipi se vuoi numeri e booleani. Niente viene caricato, quindi i segreti reali restano sul tuo dispositivo.
I valori .env sono numeri e booleani, oppure stringhe?
Sempre stringhe. dotenv non converte mai i tipi: a runtime ogni valore di process.env è una stringa, quindi PORT=8080 è "8080" e DEBUG=false è la stringa "false" (che è truthy). Qualsiasi opzione “deduci i tipi” è uno strato di comodità aggiunto sopra lo standard, non parte di dotenv stesso.
Qual è la differenza tra un file .env e un file di config JSON?
Un .env è piatto, solo stringhe, ammette i commenti ed è pensato per segreti e override per ambiente. JSON è annidato e tipizzato con numeri, booleani e null reali, e si valida contro uno schema, ma non ha commenti ed è facile da committare per sbaglio. Usa .env per i segreti, JSON per la config strutturata.
Un file .env può avere valori annidati o raggruppati?
No. Un .env è un elenco piatto di coppie KEY=VALUE senza annidamento e senza array. Per esprimere un raggruppamento, appiattiscilo con una convenzione a prefisso (DB_HOST e DB_PORT invece di un oggetto db) e ricomponi la struttura nel codice. Se ti serve davvero una gerarchia, usa JSON o YAML.
Come vengono gestiti virgolette, # e valori multiriga in .env?
Le virgolette doppie elaborano gli escape (\n, \t, \\, \") e possono estendersi su più righe fino alla virgoletta di chiusura. Le virgolette singole sono letterali, senza escape. I valori senza virgolette arrivano fino a fine riga, rimuovono lo spazio finale e trattano uno spazio seguito da # come un commento in linea, quindi metti tra virgolette qualsiasi valore che contenga legittimamente un #.
Dovrei committare il mio file .env su Git?
No. Aggiungi .env a .gitignore e committa invece un .env.example che elenca le chiavi con valori vuoti. Il file reale contiene password di database, chiavi API e token; committarlo fa trapelare le credenziali nella tua cronologia, dove persistono anche dopo che hai eliminato il file.