.env ↔ JSON Converter
Convert dotenv files to JSON and back, quotes and comments included.
Your .env secrets stay on your machineConvert a .env file to JSON
About this .env to JSON converter
Paste the contents of a .env file and get a clean JSON object, or paste JSON and get a valid .env back. The parser understands real dotenv syntax: export prefixes, full-line and inline comments, single quotes (kept literal) versus double quotes (which expand \n, \t, and \" escapes), empty values, and duplicate keys — the last one wins, with a warning. Invalid lines are reported with their line numbers so you can fix them fast.
Going the other way, strings, numbers, and booleans are written as .env values and only quoted when they need it — spaces, #, =, or line breaks. Nested objects aren’t valid in a .env file, so the tool either lists the offending keys or, with one checkbox, flattens them into uppercase DB__HOST-style keys. Environment files are exactly where API keys and database passwords live, so everything runs locally in your browser: your secrets never leave your device.
.env file format: syntax, comments and quoting rules
There is no specification for .env files. Every dotenv library implements its own dialect, so a file that loads cleanly in Node can behave differently in Python or Ruby. The table below is the common core those implementations agree on, and it is exactly what the converter above accepts, line for line.
| Rule | Example | What happens |
|---|---|---|
| One KEY=VALUE per line | DB_PORT=5432 | The value is the string "5432". A .env file carries no types, so numbers and booleans come out of the converter as JSON strings. |
| Optional export prefix | export DB_HOST=localhost | The prefix is stripped and the key is DB_HOST. Any amount of space after export is fine. |
| Full-line comment | # local development only | The line is ignored. Leading spaces before the # are allowed, and blank lines are skipped too. |
| Inline comment | PORT=3000 # dev box | The value is 3000. In an unquoted value the # only starts a comment when whitespace comes before it, so URL=site.com/#top keeps its #. |
| Unquoted value | NAME= ada | Space on both sides of the value is trimmed, giving "ada". Space around the = is trimmed as well. |
| Single quotes are literal | MSG='hi\nthere' | Nothing is expanded. The backslash and the n stay as two separate characters, and a # inside the quotes stays part of the value. |
| Double quotes expand escapes | MSG="hi\nthere" | \n, \t, \r, \" and \\ are turned into the real characters. An escape the format does not define, such as \q, is left exactly as typed. |
| Empty value | OPTIONAL= | Valid. The key exists and its value is an empty string, which is not the same as the key being absent. |
| Key naming | A-B=1 is rejected | A key must start with a letter or underscore and then use letters, digits, underscores or dots. So my.key and lower_case are accepted; a hyphen or a leading digit is not. |
| Duplicate keys | A=1 then A=2 | The last assignment wins, because a JSON object cannot hold the same key twice. The converter names the repeated key instead of picking silently. |
| Multi-line values | A quote left open at end of line | Not supported. A quoted value has to close on the same line; write \n inside double quotes to get a line break. |
# Database
export DATABASE_URL=postgres://user:pass@localhost:5432/app
PORT=3000 # inline comment: needs a space before #
GREETING="hello\nworld" # becomes a real line break
LITERAL='hello\nworld' # stays as backslash + n
EMPTY=The two things the format simply cannot do are types and nesting: a port is the string "3000", and a JSON object has nowhere to go inside a flat list of pairs. That is why the converter above reports nested keys as an error rather than inventing a shape for them.
Does ${VAR} expand? Variable expansion by loader
Whether a ${VAR} inside one value is replaced by the value of another variable depends entirely on the loader reading the file. The defaults do not agree, so it is worth knowing which one your project uses before you rely on it:
| Loader | Expands ${VAR} by default? | Literal $ / turning expansion off |
|---|---|---|
| dotenv (Node) | No | It stores the value verbatim; add the dotenv-expand package to turn on ${VAR} and $VAR expansion. |
| python-dotenv | Yes | Only braces ${VAR} expand — a bare $VAR is left as typed. Pass interpolate=False to load_dotenv() to switch it off. |
| docker compose (.env + compose file) | Yes — both ${VAR} and $VAR | Write $$ for a literal dollar sign; $$ also stops Compose interpolating what follows it. |
FAQ
Is it safe to paste a .env file with real secrets?
Yes. The conversion runs entirely in your browser — there is no upload, no server, and no logging. Your variables never leave your device, which is the whole point for files full of API keys and passwords.
How are quotes and escapes handled?
Single-quoted values stay literal, while double-quoted values expand \n, \t, and \" escapes — the same rules popular dotenv loaders use. A quoted value can’t span multiple lines: write line breaks as \n inside double quotes. When generating .env output, values are only quoted when they contain spaces, #, =, or line breaks.
What happens to nested JSON objects?
A .env file is flat, so nested objects and arrays can’t be written directly. By default the tool reports which keys are nested; enable "Flatten nested keys with __" to turn { "db": { "host": … } } into DB__HOST — a convention many config libraries read back automatically.