.env File Format: The Syntax Rules That Trip People Up

A .env file is plain text with one KEY=value pair per line. Blank lines are skipped and lines starting with # are comments. Quote a value when it holds spaces at the ends, a # sign or line breaks. There is no single standard, so dotenv for Node and Docker Compose read a few edge cases differently.

How common lines are read by dotenv
LineValue you getWhy
PORT=30003000Basic pair, always a string
EMPTY=(empty string)Empty values become empty strings
NAME= Ada AdaUnquoted values are trimmed at both ends
NAME=" Ada " Ada Quotes keep the spaces
HASH="a#b"a#bA # inside quotes is not a comment
MSG="one\ntwo"two linesDouble quotes turn \n into a line break

Updated

Most broken .env files fail on the same handful of details: a # in a password, a private key pasted over several lines, or a quote that never closes. Paste your file into the linter to see what dotenv would read for each key, and where Docker Compose would read it differently.

.env linter

Paste your .env file

# App
PORT=3000
SITE_NAME="  My Shop  "
DB_PASSWORD=abc#123
DATABASE_URL=postgres://app:$DB_PASSWORD@localhost/app
EMPTY=
PORT=8080
2FA_SECRET=xyz
PRIVATE_KEY="-----BEGIN KEY-----
MIIBOgIBAAJB
-----END KEY-----"

8 keys read, 5 with notes

What dotenv reads from each line
LineKeyValueNotes
2PORT3000
3SITE_NAME My Shop
4DB_PASSWORDabcdotenv stops at the #, but Docker Compose keeps it because no space comes before it. Quote the value.
5DATABASE_URLpostgres://app:$DB_PASSWORD@localhost/appContains $. Docker Compose expands it; plain dotenv keeps it as written.
6EMPTY(empty string)
7PORT8080Also set on line 2. Keep one so nobody has to guess which wins.
82FA_SECRETxyzNot a portable name. Shells expect letters, digits and underscores, not starting with a digit.
9PRIVATE_KEY-----BEGIN KEY----- MIIBOgIBAAJB -----END KEY-----Spans several lines inside quotes.

dotenv and Docker Compose side by side

The same line read by two loaders
Linedotenv (Node)Docker Compose
A=x#yxx#y (no space before #)
A=x #notexx
A='$HOME'$HOME$HOME (single quotes are literal)
A="$HOME"$HOMEthe value of HOME
A="x\ty"x\tyx, a tab, then y
A="x\ny"two linestwo lines

Examples you can copy

A tidy .env.example

Same keys as the real file, safe dummy values, comments explaining each group. Commit this one, never the real .env.

# Server
PORT=3000
NODE_ENV=development

# Database (ask a teammate for the real password)
DB_HOST=localhost
DB_PASSWORD="change-me#please"

# Multiline values need double quotes
TLS_CERT="-----BEGIN CERTIFICATE-----
paste-here
-----END CERTIFICATE-----"

Load it in Node

config() reads .env from the current working directory by default. Values already in the environment stay as they are.

// index.js
require("dotenv").config();

const port = Number(process.env.PORT || 3000);
console.log("Listening on", port);

Where dotenv and Docker Compose part ways

Inline comments are the classic trap. Compose needs whitespace before the # in an unquoted value, while dotenv cuts the value at the first # it sees. Both ignore a # that sits inside quotes.

Expansion is the other one. Compose replaces $VAR and ${VAR} inside unquoted and double-quoted values, and leaves single-quoted values untouched. Plain dotenv returns the dollar sign and name exactly as written.

Keeping .env files safe

A .env file usually holds database passwords and API keys, so treat it like any other secret. Keep it out of version control, give it tight file permissions on servers, and rotate any value that was ever committed by mistake.

Prefer your host's secret settings for production. The file is a convenience for local development, not a vault.

How it works

  1. Paste the contents of your .env file into the box, or edit the sample that is already there.
  2. Each key is listed with the value dotenv would hand your program, after quotes and comments are handled.
  3. Notes flag real problems (no = sign, a quote that never closes, a repeated key) and portability warnings.
  4. Fix the line, watch the note disappear, then copy your cleaned file back into your project.

Tips

Frequently asked questions

Is there an official .env file specification?

No. The format grew out of shell variable assignments and each loader documents its own rules. The dotenv package for Node and Docker Compose both publish theirs, and they agree on the basics: KEY=value lines, # comments and quoted values.

Should I put quotes around values in a .env file?

Only when you need them. Quotes are required for values with a # sign, leading or trailing spaces, or line breaks. Use single quotes in Compose when you want a $ to stay literal, because single-quoted values are not interpolated there.

How do I write a multiline value such as a private key?

Wrap it in double quotes and keep the real line breaks, which dotenv supports from version 15.0.0. You can also keep it on one line and write \n where each break goes, since double-quoted values turn \n into a newline.

Can I put a comment at the end of a line?

Yes, with care. dotenv treats an unquoted # as the start of a comment. Docker Compose only does so when a space comes before the #, so KEY=a#b gives a#b in Compose but a in dotenv. Leave a space before inline comments to be safe.

Does dotenv overwrite variables that are already set?

No. By default dotenv never changes a variable that already exists in the environment, so a value set by your shell or host wins. Pass the override option set to true if you want the file to replace them.

Related: Next.js environment variables, Docker Compose env_file, Git cheat sheet, Regex cheat sheet.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap