Complete .env Guide
1. What is .env
.env = environment variables file
= a file that stores sensitive or environment-specific values
outside your actual code
Simple text file. Just key=value pairs.
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
JWT_SECRET=mysecretkey123
PORT=5000
2. Where .env is Used — React, Node or Both
Both use .env but for different purposes.
main-folder/
├── react/
│ └── .env ← React's own .env
├── nodejs/
│ └── .env ← Node's own .env
└── docker-compose.yml
React .env — Frontend Config Only
REACT_APP_API_URL=https://yourdomain.com/api
REACT_APP_GOOGLE_MAPS_KEY=AIzaSyXXXXXXXX
REACT_APP_APP_NAME=MyApp
Rule: React env variables MUST start with REACT_APP_
Otherwise React ignores them completely.
Node .env — Backend + Database + Secrets
PORT=5000
DATABASE_URL=postgres://user:pass@db:5432/mydb
JWT_SECRET=supersecretkey
EMAIL_USER=noreply@yourdomain.com
EMAIL_PASS=emailpassword123
RAZORPAY_KEY=rzp_live_XXXXXXXX
RAZORPAY_SECRET=XXXXXXXXXXXXXXX
NODE_ENV=production
3. What Each .env Variable Does
Node .env breakdown
PORT=5000
# Which port your Node server runs on
DATABASE_URL=postgres://user:pass@db:5432/mydb
# Full connection string to Postgres
# user = postgres username
# pass = postgres password
# db = docker service name (hostname)
# 5432 = postgres port
# mydb = database name
JWT_SECRET=supersecretkey
# Used to sign and verify login tokens
# If leaked → anyone can fake login as any user
NODE_ENV=production
# Tells your app which environment it is running in
# Changes behavior — logging, error messages, optimizations
EMAIL_USER=noreply@yourdomain.com
EMAIL_PASS=emailpassword123
# SMTP credentials for sending emails
RAZORPAY_KEY=rzp_live_XXXXXXXX
RAZORPAY_SECRET=XXXXXXXXXXXXXXX
# Payment gateway credentials
React .env breakdown
REACT_APP_API_URL=https://yourdomain.com/api
# The base URL React uses to call your Node API
# In development → http://localhost:5000/api
# In production → https://yourdomain.com/api
REACT_APP_GOOGLE_MAPS_KEY=AIzaSyXXXXXXXX
# Public API keys that browser needs directly
4. How .env is Used in Code
In Node (server.js)
// First install dotenv package
// npm install dotenv
// At top of server.js
require('dotenv').config()
// Now use anywhere in your code
const PORT = process.env.PORT
const db = process.env.DATABASE_URL
const secret = process.env.JWT_SECRET
// Example usage
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`)
})
// Database connection
const pool = new Pool({
connectionString: process.env.DATABASE_URL
})
// JWT signing
const token = jwt.sign(payload, process.env.JWT_SECRET)
In React (any component)
// No extra package needed
// React reads .env automatically at build time
const API_URL = process.env.REACT_APP_API_URL
// Example usage
const response = await fetch(`${API_URL}/users`)
// In development hits → http://localhost:5000/api/users
// In production hits → https://yourdomain.com/api/users
5. How .env Helps in Production
The Problem Without .env
// BAD — values hardcoded in code
const pool = new Pool({
host: 'localhost',
password: 'mypassword123', // visible to everyone
database: 'mydb'
})
// pushed to git → anyone who sees your repo
// sees your database password
The Solution With .env
// GOOD — values come from environment
const pool = new Pool({
connectionString: process.env.DATABASE_URL
// actual password never appears in code
// never pushed to git
})
Production Benefits
Local .env Production .env
────────────────── ──────────────────────────
DATABASE_URL=localhost DATABASE_URL=prod-db-server
NODE_ENV=development NODE_ENV=production
JWT_SECRET=devkey123 JWT_SECRET=Xk9#mP2$qL8@nR5!
PORT=5000 PORT=5000
Same code runs in both environments
Just .env values change
No code changes needed
6. .env and .gitignore — Critical Step
.env must NEVER be pushed to git.
# Create .gitignore in each folder
nano .gitignore
# Inside .gitignore
.env
node_modules/
build/
git push
↓
.gitignore blocks .env from uploading
↓
Git repo has NO passwords or secrets
↓
Safe to make repo public or share with team
What gets pushed vs what stays local
Gets pushed to git Stays on machine only
────────────────── ──────────────────────
server.js .env
package.json node_modules/
Dockerfile build/
docker-compose.yml
.gitignore
.env.example ← this gets pushed (see below)
7. .env.example — Industry Standard Practice
You push a .env.example file to git so teammates know what variables are needed — but with no real values.
# nodejs/.env.example
PORT=
DATABASE_URL=
JWT_SECRET=
NODE_ENV=
EMAIL_USER=
EMAIL_PASS=
RAZORPAY_KEY=
RAZORPAY_SECRET=
# react/.env.example
REACT_APP_API_URL=
REACT_APP_GOOGLE_MAPS_KEY=
New developer joins team:
git clone repo
cp .env.example .env
# fill in real values
# app runs immediately
8. If .env is NOT Used — Pros and Cons
Pros (almost none)
✓ Slightly simpler for a throwaway script
✓ One less file to manage
Cons (serious problems)
✗ Passwords hardcoded in code
→ visible to anyone with repo access
✗ Code pushed to GitHub with real credentials
→ bots scan GitHub and steal credentials within minutes
✗ Different values for dev and production
→ must manually change code every deployment
→ high risk of deploying wrong values
✗ Team members see production passwords
→ security risk
✗ Payment keys, JWT secrets in plain code
→ major security breach risk
✗ Cannot change password without changing code
→ requires new git commit and deployment
9. How to Create .env — Step by Step
Local Development
# Go into nodejs folder
cd nodejs
# Create .env file
touch .env
# Open and add variables
nano .env
PORT=5000
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
JWT_SECRET=devlocalsecretkey
NODE_ENV=development
EMAIL_USER=test@gmail.com
EMAIL_PASS=testpassword
# Go into react folder
cd ../react
# Create .env file
touch .env
nano .env
REACT_APP_API_URL=http://localhost:5000/api
REACT_APP_APP_NAME=MyApp
On Production Server
# SSH into server
ssh user@your-server-ip
# Go to your project
cd /home/user/your-repo/nodejs
# Create production .env
nano .env
PORT=5000
DATABASE_URL=postgres://user:strongpassword@db:5432/mydb
JWT_SECRET=Xk9#mP2$qL8@nR5!vB3&wZ7
NODE_ENV=production
EMAIL_USER=noreply@yourdomain.com
EMAIL_PASS=realemailpassword
RAZORPAY_KEY=rzp_live_XXXXXXXX
RAZORPAY_SECRET=XXXXXXXXXXXXXXX
10. .env with Docker — How It Connects
Option 1 — Docker reads .env file directly
# docker-compose.yml
services:
backend:
build: ./nodejs
env_file:
- ./nodejs/.env ← docker reads this file
ports:
- "5000:5000"
db:
image: postgres:15
env_file:
- ./nodejs/.env ← postgres gets credentials from same file
Option 2 — Hardcode in docker-compose (not recommended)
services:
backend:
environment:
- PORT=5000
- JWT_SECRET=mysecret ← secret visible in docker-compose
Option 1 is always better — secrets stay in .env, not in docker-compose.
11. Industry Standard Summary
Rule 1: .env never goes to git
Rule 2: .env.example always goes to git
Rule 3: Production .env has stronger secrets than dev
Rule 4: Never hardcode passwords, keys, URLs in code
Rule 5: Each environment has its own .env
(local, staging, production)
Rule 6: Rotate secrets regularly (change passwords periodically)
Rule 7: Minimum access — .env only contains what that service needs
12. Complete Picture
YOUR CODE (git repo) YOUR SECRETS (.env)
──────────────────── ──────────────────────
server.js PORT=5000
process.env.PORT ←─── DATABASE_URL=postgres://...
process.env.JWT_SECRET ←─── JWT_SECRET=Xk9#mP2$...
process.env.DATABASE_URL ←─── NODE_ENV=production
Code is public safe .env stays private
Push to git freely Never pushed to git
Same code everywhere Different per environment
One codebase. Multiple environments. Zero hardcoded secrets. That is the purpose of .env.
No comments:
Post a Comment