Environment Variables
Managing configuration and secrets with environment variables — patterns for organizing and validating them.
Environment Variables
Environment variables keep secrets and configuration out of your code. This file covers the full list used across this section, plus a pattern for organizing and validating them in one place.
Full .env Reference
This is the complete list of environment variables used across every file in this Starter Code section. Not every project needs all of them — add what you use.
# .env
# Server
PORT=5000
NODE_ENV=development
# Database
MONGO_URI=mongodb+srv://username:password@cluster.mongodb.net/myapp
# Authentication
JWT_SECRET=your_access_token_secret_min_32_chars
JWT_REFRESH_SECRET=your_refresh_token_secret_min_32_chars
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d
# Frontend connection
CLIENT_URL=http://localhost:5173
# Email (Nodemailer)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your_email@gmail.com
SMTP_PASS=your_app_password
# File uploads (Cloudinary)
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# OAuth (Google)
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secretA Centralized Config File
Instead of scattering process.env.X across every file, create one config file that reads and exports all environment variables. This makes it easy to see everything in one place and catch missing variables early.
// src/config/env.js
import dotenv from "dotenv";
dotenv.config();
const env = {
port: process.env.PORT || 5000,
nodeEnv: process.env.NODE_ENV || "development",
mongoUri: process.env.MONGO_URI,
jwtSecret: process.env.JWT_SECRET,
jwtRefreshSecret: process.env.JWT_REFRESH_SECRET,
jwtExpiresIn: process.env.JWT_EXPIRES_IN || "15m",
jwtRefreshExpiresIn: process.env.JWT_REFRESH_EXPIRES_IN || "7d",
clientUrl: process.env.CLIENT_URL || "http://localhost:5173",
smtp: {
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
cloudinary: {
cloudName: process.env.CLOUDINARY_CLOUD_NAME,
apiKey: process.env.CLOUDINARY_API_KEY,
apiSecret: process.env.CLOUDINARY_API_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
};
export default env;Usage anywhere in the app:
// instead of this everywhere:
// process.env.JWT_SECRET
// do this:
import env from "../config/env.js";
jwt.sign(payload, env.jwtSecret, { expiresIn: env.jwtExpiresIn });Validating Required Variables
Catch missing critical environment variables on startup instead of getting a confusing error later when a route is hit.
// src/config/validateEnv.js
const requiredVars = ["MONGO_URI", "JWT_SECRET", "JWT_REFRESH_SECRET"];
const validateEnv = () => {
const missing = requiredVars.filter((key) => !process.env[key]);
if (missing.length > 0) {
console.error(`Missing required environment variables: ${missing.join(", ")}`);
process.exit(1);
}
};
export default validateEnv;Call it at the very top of server.js, right after loading dotenv:
// server.js
import dotenv from "dotenv";
dotenv.config();
import validateEnv from "./src/config/validateEnv.js";
validateEnv(); // exits immediately if anything critical is missing
import app from "./src/app.js";
import connectDB from "./src/config/db.js";
// ...rest of server.jsThis catches a missing JWT_SECRET the moment the server starts, instead of someone discovering it three days later when a login route mysteriously fails in production.
NODE_ENV — Common Pattern
NODE_ENV controls environment-specific behavior — different error detail, different logging, different CORS rules.
// example usage in error middleware
if (env.nodeEnv === "development") {
res.status(500).json({ message: error.message, stack: error.stack });
} else {
res.status(500).json({ message: "Something went wrong" });
}Stack traces are useful in development, but should never be exposed to users in production.
Summary
- A centralized
env.jsconfig file reads allprocess.envvalues once and exports them — cleaner thanprocess.env.Xscattered everywhere validateEnv()checks for required variables on startup and exits immediately if any are missing — fails fast instead of failing mysteriously laterNODE_ENVis used throughout the app to toggle behavior between development and production — most commonly in error handling- The full
.envreference above covers every variable used across this Starter Code section — add only what your project actually needs