We've all been there - your Node.js app works perfectly locally, you deploy to production, and suddenly:
Error: Cannot read property 'API_KEY' of undefined
Or worse - your app starts but silently fails because process.env.DATABASE_URL is undefined, and you only notice when users start complaining.
Here's how to catch these issues before they reach production.
The Problem
Environment variables are essential for Node.js apps, but they're easy to mess up:
-
Typos:
process.env.API_KEyinstead ofprocess.env.API_KEY - Unused variables cluttering your .env file (security risk)
- Missing variables in production that exist locally
- Variables defined but never used (confusing for new team members)
- AWS Secrets Manager mismatches - your code expects variables that don't exist in Parameter Store
Real-World Example
// In your code
const dbHost = process.env.AURORA_HOST;
const dbPort = process.env.AURORA_PORT;
// In your serverless.yml
environment:
AURORA_HOST: ${self:custom.secrets_AURORA.host}
AURORA_PORT: ${self:custom.secrets_AURORA.port}
// But did you actually create those nested keys in AWS Secrets Manager?
// You won't know until deployment fails... π₯
Solutions
Manual Approach
Create a checklist, review .env files before each deployment, manually verify AWS resources... boring, error-prone, and doesn't scale.
Automated Verification
I built a tool to automate this (because I kept making these mistakes):
npm install -g @danielszlaski/envguard
envguard scan
What it catches:
β
Variables used in code but not defined
β
Variables defined but never used
β
Typos in variable names
β
Missing fallback handling
Example output:
β Missing Variables:
β’ DATABASE_URL (used in src/db/connection.js:12)
β’ API_KEY (used in src/services/api.js:8)
β Unused Variables:
β’ OLD_LEGACY_VAR (defined in .env but never used)
Taking It Further: CI/CD Integration
Finding issues on your laptop is good. Preventing them from reaching your repo is better.
Git Hooks (Pre-Commit/Pre-Push)
The pro version includes automatic Git hook installation:
# Install pre-commit hook
envguard install-hook
# Install pre-push hook instead
envguard install-hook --type pre-push
Now every commit/push automatically runs validation:
Running envguard scan...
β Missing Variables:
β’ NEW_FEATURE_FLAG (used in src/features/new.js:5)
Pre-commit hook failed. Fix the issues above or use --no-verify to skip.
GitHub Actions / CI Pipeline
Add to your .github/workflows/ci.yml:
- name: Validate Environment Variables
run: |
npm install -g @danielszlaski/envguard
envguard scan --ci
The --ci flag makes the command exit with code 1 if issues are found, failing your pipeline.
SARIF Output for GitHub Security Tab
For compliance and security tracking:
envguard scan --format sarif --output results.sarif
Then upload to GitHub Security:
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: results.sarif
Now environment variable issues appear in your Security tab alongside other vulnerabilities.
AWS Integration: The Missing Piece
Here's a scenario I've seen too many times:
- You define variables in
serverless.ymlreferencing AWS Secrets Manager - You deploy successfully (because Serverless just reads the config)
- Your app starts but crashes at runtime because the secrets don't exist in AWS
Solution: Pre-Deployment AWS Validation
# Validate that AWS resources exist
envguard scan --aws
# Also validate nested keys within secrets (deep validation)
envguard scan --aws --aws-deep
Example serverless.yml:
custom:
secrets_AURORA: ${ssm:/aws/reference/secretsmanager/myapp/dev/aurora}
provider:
environment:
AURORA_HOST: ${self:custom.secrets_AURORA.host}
AURORA_PORT: ${self:custom.secrets_AURORA.port}
AURORA_USER: ${self:custom.secrets_AURORA.username}
Without validation: Deploy β Runtime crash β "Secret key 'username' not found"
With --aws-deep:
β All AWS resources validated successfully
Secrets Manager (1):
β’ myapp/dev/aurora
ββ host β
ββ port β
ββ username β MISSING
β Missing Secret Keys:
β’ myapp/dev/aurora.username (used by AURORA_USER)
You catch the issue before deployment.
Required IAM Permissions
For basic validation (--aws):
ssm:GetParametersecretsmanager:DescribeSecret
For deep validation (--aws-deep):
-
secretsmanager:GetSecretValue(to fetch and parse JSON)
Smart Fallback Detection
Not all missing variables are critical. EnvGuard detects defensive coding patterns:
// These are warnings (not errors)
const apiUrl = process.env.API_URL || 'https://default-api.com';
const timeout = process.env.TIMEOUT ?? 5000;
const debug = process.env.DEBUG ? true : false;
// This is an error (no fallback)
const dbUrl = process.env.DATABASE_URL; // Will be undefined!
Why this matters: You can prioritize fixing actual errors while staying aware of all env var usage.
Disable this if you want strict checking:
envguard scan --no-detect-fallbacks
Configuration File
Create .envguardrc.json:
{
"ignoreVars": ["NODE_ENV", "CI"],
"strict": false,
"detectFallbacks": true,
"exclude": ["**/node_modules/**", "**/dist/**"],
"envFiles": ["set-env.sh"]
}
Pro tip: The envFiles option lets you scan shell scripts too:
# In your set-env.sh
export API_KEY="abc123"
export DATABASE_URL="postgres://..."
# EnvGuard will pick these up
envguard scan --env-files set-env.sh
Complete CI/CD Workflow
Here's my production setup:
1. Local development: Pre-commit hook catches issues immediately
2. GitHub Actions:
name: Validate Environment
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate env vars
run: |
npm install -g @danielszlaski/envguard
envguard scan --ci --aws --aws-deep
env:
AWS_REGION: eu-west-1
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: results.sarif
3. Pre-deployment: Final check before Serverless deploy
envguard scan --ci --aws --aws-deep && serverless deploy
Best Practices Summary
- Automate validation - don't rely on manual checks
- Fail fast - catch issues in Git hooks, not production
- Validate AWS resources - don't assume secrets exist
- Track in Security tab - use SARIF for compliance
- Use fallbacks wisely - but be aware of all env usage
-
Document required variables -
.envguardrc.jsonserves as documentation
Try It Out
Free version:
npm install -g @danielszlaski/envguard
envguard scan
Pro version (AWS integration, Git hooks, SARIF output):
https://envguard.pl - 39 PLN (~β¬9)
What Environment Variable Nightmares Have You Experienced?
Drop a comment below - I'd love to hear your war stories and add more detection patterns to the tool!
Links:
- Free version: https://www.npmjs.com/package/@danielszlaski/envguard
- Documentation: https://envguard.pl
- GitHub: https://github.com/szlaskidaniel/envguard
Top comments (0)