.env File Syntax and What to Know About Environment Variables
A .env file is a simple format: one KEY=value per line. But no official standard defines that simplicity, so details like quoting and multi-line values behave differently across libraries. This tool breaks pasted .env content into key-value pairs so you can see what a parser actually reads.
Basic syntax
By convention keys use only uppercase letters and underscores, because they must be exportable as shell environment variables — a key containing a hyphen can't be handled by a shell. Avoid spaces around the equals sign too: written as KEY = value, some parsers produce the key "KEY " and others the value " value".
# comments start with # NODE_ENV=production PORT=3000 # quote values containing spaces APP_NAME="My Application" # empty values are valid OPTIONAL_FLAG= # values full of special characters, like URLs DATABASE_URL=postgres://user:pass@localhost:5432/mydb # multi-line values (only in parsers that support them) PRIVATE_KEY="-----BEGIN PRIVATE KEY----- MIIEvQIBADANBg... -----END PRIVATE KEY-----"
How to use it
- Paste your .env content.
- Review the parsed key-value list — confirm each value is what you intended and that quotes aren't part of the value.
- If a value looks truncated, check the quoting and special-character section below.
- Copy the results into your code or deployment configuration.
When quoting is needed, and its side effects
The most common real incident involves $ and # inside passwords. Some parsers expand $VAR as a reference to another variable and discard everything after a #, so the password is silently truncated and shows up as an authentication failure — and since you don't log passwords, diagnosing it takes a long time. Wrapping values with special characters in single quotes is the safest choice.
| Written as | Parses to | Notes |
|---|---|---|
| KEY=hello | hello | The simplest form |
| KEY="hello world" | hello world | The quotes are stripped |
| KEY=hello world | hello world or hello | Parser-dependent — use quotes |
| KEY="line1\nline2" | A value containing a newline | \n is interpreted only in double quotes |
| KEY='line1\nline2' | The literal text line1\nline2 | Single quotes don't interpret escapes |
| KEY=value # comment | value, or value # comment | Inline comment support varies |
| KEY=pa$$word | pa, or pa$$word | $ may be treated as variable expansion |
Environment variables are only ever strings
At the OS level an environment variable's value is always a string, and that produces a classic bug. Setting DEBUG=false still gives you the string "false" in process.env.DEBUG, and since any non-empty string is truthy in JavaScript, if (process.env.DEBUG) passes. Numbers behave the same way: PORT=3000 is "3000", so arithmetic silently becomes string concatenation.
The recommended pattern is to validate and coerce all of them in one place at startup. Defining a schema with zod or envalid means the application dies with a clear error at boot when a required value is missing — far better than behaving strangely mid-run because something was undefined.
import { z } from "zod";
const env = z.object({
NODE_ENV: z.enum(["development", "production", "test"]),
PORT: z.coerce.number().default(3000),
DEBUG: z.stringbool().default(false),
DATABASE_URL: z.string().url(),
}).parse(process.env);
// downstream, env.PORT is a real number
export default env;Precedence and multiple files
Most libraries will not overwrite a real environment variable that is already set with a value from a .env file — so anything exported in your shell or injected into your container wins. That's deliberate: in a deployed environment, platform-injected values should take precedence over files.
There's also a convention of splitting files: .env for shared defaults, .env.local for personal machine-specific settings (not committed), and .env.production for per-environment values. Tools like Next.js and Vite define a fixed load order, so when a value isn't what you expect, work out which file won.
Security essentials
- Put .env in .gitignore, and commit a .env.example listing the key names with empty values so the team knows what's required.
- If it's already committed, removing it from history isn't enough — rotate the exposed credentials immediately. If the repo was ever public, assume automated scanners already have them.
- Know which variables are exposed to the client. Values prefixed NEXT_PUBLIC_ (Next.js) or VITE_ (Vite) are embedded in the browser bundle, so putting a secret behind that prefix publishes it instantly.
- Production secrets belong in a secret manager (AWS Secrets Manager, GCP Secret Manager, Vault) rather than a file, which gives you access auditing and rotation.
- Never dump environment variables into CI logs. Output from env or printenv exposes them to everyone with log access.
Frequently Asked Questions
- Is what I paste sent to a server?
- No, parsing happens in your browser. Even so, don't paste a .env holding real production credentials into a third-party site. If you're checking syntax, substitute dummy values first.
- How do I put a newline in a value?
- Where the parser supports it, wrap in double quotes and either embed a real newline or use a \n escape. Because support varies, multi-line values like RSA private keys are commonly Base64-encoded into a single line and decoded in code instead. When entering values directly in a platform's UI, multi-line input usually works as-is.
- My value gets cut off at a # character.
- It was read as an inline comment. Wrapping the whole value in quotes fixes it. For passwords containing #, $, spaces, or quotes, single quotes are the most predictable choice.
- Why aren't my .env values taking effect?
- Check in this order: is the file in the process's working directory (running from a subdirectory won't find it)? Does the loading code run before your other imports? Is a same-named variable already set in the shell and winning? And is the filename exactly right — saving as .env.txt is a common slip.
- Can keys contain hyphens?
- Some parsers accept them, but don't. Hyphenated names can't be exported as shell environment variables, which breaks portability between tools. Underscores are both the convention and the practical choice.
- Is an empty value different from an undefined one?
- Yes. KEY= sets an empty string; omitting it leaves undefined. In JavaScript, process.env.KEY ?? "default" preserves an empty string while process.env.KEY || "default" replaces it. That distinction causes surprises, so decide which behavior you want.
💡 Note: When a value seems wrong, check the parse result here first. Usually the quotes ended up inside the value, or it was truncated at a special character.