.env files seem like the most harmless thing in the world.
A variable, an equals sign, a value. Everything is nice and simple.
Then comes the moment when someone — especially our beloved AIs — decides to do something that looks perfectly reasonable:
DB_PORT=27017 # MongoDB port
NODE_ENV=production # Production environment
And so it begins…
The problem is that not every .env file parser handles inline comments properly. Some understand perfectly well that everything after # is a comment. Others decide to grab the entire line and start fluttering around like a moth against a streetlight.
So you think you have:
DB_PORT=27017
while your software may actually end up with something like:
DB_PORT="27017 # MongoDB port"
Wonderful.
Personally, I ran into this with Go. Don’t ask me which parser it was because I don’t remember, but I’ve seen similar behaviour during builds and startups managed with Docker Compose as well.
The funny part is that these problems often don’t blow up in your face immediately.
If the variable represents something important and critical, the program might die straight away and at least give you a clue.
But if it represents a non-essential application value, a secondary feature flag, an endpoint used only under certain conditions, or simply some damn token, completely nonsensical malfunctions can start showing up.
And that’s when the time starts disappearing.
Why? Because you may find yourself in a situation where:
- everything works locally;
- it doesn’t work on the server;
- the code is identical;
- the configuration looks identical;
- you’ve already checked the variable seven times;
- you start questioning your own sanity.
Meanwhile, the local version of your software keeps running perfectly happily like a fairground ride.
No More Comments Next to Variables
The solution I adopted is very simple:
I no longer want to see comments on the same line as variables in .env files.
So this:
DB_PORT=27017 # MongoDB port
REDIS_HOST=10.0.0.14 # Redis Cluster
must become this:
# MongoDB port
DB_PORT=27017
# Redis Cluster
REDIS_HOST=10.0.0.14
The comment is still there, and the configuration remains readable.
Automatically Cleaning a .env File
Obviously, I had absolutely no intention of manually fixing dozens or hundreds of lines.
So we can let Perl do the dirty work (thanks, fatChatGPT):
perl -pe 'if (/^(\s*[^#\s][^=]*=.*?)[ \t]+#\s*(.+?)\s*$/) { $_ = "# $2\n$1\n"; }' .env > .env-treated
The command takes:
DB_HOST=10.0.0.15
DB_PORT=27017 # MongoDB port
DB_PASSWORD=test#123
REDIS_HOST=10.0.0.14 # Redis Cluster
NODE_ENV=production # Environment
and produces a new .env-treated file:
DB_HOST=10.0.0.15
# MongoDB port
DB_PORT=27017
DB_PASSWORD=test#123
# Redis Cluster
REDIS_HOST=10.0.0.14
# Environment
NODE_ENV=production
No magic. The comment is simply moved above the variable.
Watch Out for # Characters That Are Actually Part of the Value
There is, however, one important detail here.
A # character can legitimately be part of a password, a token, or any other value.
For example:
PASSWORD=test#123
TOKEN=abc#xyz
These lines must not be touched.
That’s why the command treats a # as an inline comment only when it is preceded by at least one space or tab.
So:
PASSWORD=test#123
remains:
PASSWORD=test#123
while:
PASSWORD=test#123 # Service password
becomes:
# Service password
PASSWORD=test#123
Exactly what we want.
A Convenient Bash Function
If this happens to you often, you might as well create a function:
envclean() {
perl -pe 'if (/^(\s*[^#\s][^=]*=.*?)[ \t]+#\s*(.+?)\s*$/) { $_ = "# $2\n$1\n"; }' "$1" > "${1}-treated"
}
Then:
envclean .env.production
generates:
.env.production-treated
without modifying the original file.
Which is always a good idea, because automating configuration cleanup is useful; automating the destruction of the original configuration, slightly less so.
In Conclusion
Inline comments in .env files are nice as long as they work.
The problem is that we can’t know for certain which parser will read that file today, tomorrow, or inside some container assembled by someone six months from now.
So the rule I prefer is:
A comment goes above. A variable goes below. Never together on the same line.
It’s slightly more verbose, but it also makes it much less likely that you’ll spend an afternoon debugging a token that accidentally contains " # production token" at the end.
I hope that, like me, you have more creative ways to waste your time.

