I'm trying to figure out the best way to organize my environment variables. I usually have a .env file for local development and use PM2 for production configurations. The problem is that my .env file keeps getting larger, mixing different types of variables:
- **Config**: This includes non-sensitive settings like PORT, API_URL, LOG_LEVEL, and feature flags.
- **Secrets**: This consists of sensitive information such as API keys, database credentials, and JWTs.
Do you separate these types of variables? For example, do you keep configs directly in the code with defaults, and put secrets in the .env file? Or do you use separate files? I'm curious about what works best for you in your day-to-day development.
5 Answers
You know, I just keep things simple. My .env contains all secrets and keys, which I update each time I deploy. It works for me, but I can see why having stricter separation is better as projects grow.
For me, I use .env files locally but most platforms have their own secret management systems now. It's okay if your .env file grows, but remember that you don't have to keep everything in it. Some configurations can be hardcoded right into your app.
Here’s a handy rule: anything that can leak without catastrophic consequences can be in config, while secrets that would be damaging if exposed should be isolated in a separate environment or vault. This helps clarify what goes where.
I believe configurations should be in your code, while secrets should be stored securely, like in a vault. When I started out, everything was hardcoded into the app, which was a mess! Now, we use a vault for secrets and keep non-sensitive config values in the code with sane defaults for production and local development. The tiny bit of sensitive data that does need to stay outside the code can go in a .env file.
That’s the way to go! A separated secure approach avoids mixing essential configurations and keeps everything clean.
After dealing with a bloated .env, I switched to a split system. Non-sensitive values are held in a config.js file with defaults set, while real secrets are stored in an ignored .env file. This keeps my repo clean. Plus, we have a validateConfig function that checks everything at startup, avoiding nasty surprises on production.

Exactly! We went through a similar evolution, and using a vault has saved us a ton of headaches.