process & Environment Variables

Node.js · Lesson 9 of 30 9 min read Updated

Every running Node.js program has a global object called process. It describes the program itself: which version of Node.js runs it, which arguments you typed, which folder it started in, and the environment variables it can read. It also lets the program exit with a success or failure code and react when someone presses Ctrl+C.

The most important part for web developers is configuration. Your database password, your port number and your API keys must not be written into the code. In this lesson you will read them from environment variables, load them from a .env file with the built-in --env-file option, and check them when the program starts.

Facts about the running program

JavaScript
console.log(`Node.js ${process.version}`);
console.log(`Platform: ${process.platform}, CPU: ${process.arch}`);
console.log(`Folder: ${process.cwd()}`);

const mb = (bytes) => `${Math.round(bytes / 1024 / 1024)} MB`;
console.log(`Memory used: ${mb(process.memoryUsage().rss)}`);
console.log(`Running for: ${process.uptime().toFixed(2)} s`);
Output
Node.js v26.13.0
Platform: win32, CPU: x64
Folder: C:\node-course
Memory used: 50 MB
Running for: 0.74 s

process.cwd() is the current working directory, the folder you ran the command from. memoryUsage().rss is the total memory the process uses. Your numbers will be different.

Command-line arguments

process.argv is an array of everything on the command line. The first two items are the path to node and the path to your script; your own arguments start at index 2.

JavaScript
// args.js
console.log(process.argv);
const [, , ...args] = process.argv;
console.log(args);
Terminal
node args.js Kochi 3 --fast
Output
[
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\node-course\\args.js',
  'Kochi',
  '3',
  '--fast'
]
[ 'Kochi', '3', '--fast' ]

Every argument is a string, even 3. For anything more than one or two arguments, use the built-in parseArgs() from node:util. It understands options such as --city Lucknow and short forms such as -t 2:

JavaScript
// greet.js
import { parseArgs } from "node:util";

const { values, positionals } = parseArgs({
  options: {
    city: { type: "string", short: "c", default: "Delhi" },
    times: { type: "string", short: "t", default: "1" },
    shout: { type: "boolean", short: "s" },
  },
  allowPositionals: true,
});

const name = positionals[0] ?? "friend";
let message = `Namaste ${name} from ${values.city}!`;
if (values.shout) message = message.toUpperCase();

for (let i = 0; i < Number(values.times); i++) console.log(message);
Terminal
node greet.js Farhan --city Lucknow -t 2
node greet.js Isha -s
Output
Namaste Farhan from Lucknow!
Namaste Farhan from Lucknow!
NAMASTE ISHA FROM DELHI!

An unknown option such as --colour throws an error with the code ERR_PARSE_ARGS_UNKNOWN_OPTION, so typing mistakes do not pass silently. Positionals are the arguments that are not options, here the name.

Environment variables

An environment variable is a named setting that the operating system gives to every program it starts. Node.js puts them all in process.env. They let the same code run with different settings on your laptop, on a test server and in production, and they keep secrets out of your source code.

JavaScript
// config.js
const port = Number(process.env.PORT ?? 3000);
const mode = process.env.NODE_ENV ?? "development";
const dbHost = process.env.DB_HOST ?? "127.0.0.1";

console.log(`Port: ${port} (${typeof port})`);
console.log(`Mode: ${mode}`);
console.log(`DB host: ${dbHost}`);
console.log(`DB password set: ${Boolean(process.env.DB_PASSWORD)}`);

Set variables for one run in the terminal. The syntax depends on your shell:

Terminal
# macOS, Linux, Git Bash
PORT=8080 NODE_ENV=production node config.js
PowerShell
# Windows PowerShell (stays set until you close the window)
$env:PORT = "8080"; $env:NODE_ENV = "production"; node config.js
Output
Port: 8080 (number)
Mode: production
DB host: 127.0.0.1
DB password set: false

Values in process.env are always strings (or undefined if not set), so convert numbers with Number() and give defaults with ??. Never print secret values in logs; print only whether they are set, as the code above does. NODE_ENV is a common convention: many libraries, including Express, behave differently when it is "production".

.env files and --env-file

Typing many variables every time is tiring. Instead, keep them in a file called .env in the project folder:

Terminal
# .env: settings for local development
PORT=4000
DB_HOST=127.0.0.1
DB_PASSWORD="s3cret pass"   # quotes keep the space

Node.js can load it for you with the --env-file option. No package is needed:

Terminal
node --env-file=.env config.js
Output
Port: 4000 (number)
Mode: development
DB host: 127.0.0.1
DB password set: true

Useful rules:

  • Lines starting with # are comments, and so is text after # at the end of a line. Wrap values in quotes when they contain spaces or #.
  • A variable that is already set in the real environment wins over the file. Running PORT=9000 node --env-file=.env config.js uses port 9000. This lets a server override the file.
  • You can pass several files: --env-file=.env --env-file=.env.local. Later files override earlier ones.
  • --env-file stops with an error if the file is missing. Use --env-file-if-exists=.env when the file is optional, for example in production where real variables are used instead.

To load a file from inside your code, call process.loadEnvFile(). With no argument it reads .env in the current folder.

Checking configuration at startup

A server that starts without its database password fails later in confusing ways. Check the required settings first and stop with a clear message:

JavaScript
try {
  process.loadEnvFile(); // reads ./.env
} catch {
  console.log("No .env file, using defaults");
}

const required = ["DB_HOST", "DB_PASSWORD", "JWT_SECRET"];
const missing = required.filter((name) => !process.env[name]);

if (missing.length > 0) {
  console.error(`Missing environment variables: ${missing.join(", ")}`);
  process.exitCode = 1;
} else {
  console.log("Configuration OK");
}
Output
Missing environment variables: JWT_SECRET

Exit codes and shutting down

When a program ends, it returns an exit code to the system: 0 means success and any other number means failure. Scripts, test tools and process managers read it. Setting process.exitCode = 1 marks the run as failed but lets Node.js finish its pending work and exit normally. process.exit(1) stops immediately, which can cut off logs that have not been written yet, so prefer exitCode.

Servers should also stop gracefully: finish the requests in progress and close database connections when someone presses Ctrl+C (the SIGINT signal) or a hosting platform asks the process to stop (SIGTERM):

JavaScript
function shutdown(signal) {
  console.log(`${signal} received, closing the server...`);
  server.close(() => {
    console.log("All connections closed. Bye!");
  });
}

process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);

Here server is the HTTP server you will create in The http Module.

Common mistakes

  • Writing secrets in code. Passwords in source files end up on GitHub. Read them from process.env.
  • Forgetting values are strings. process.env.DEBUG === true is always false; compare with "true", and convert numbers with Number().
  • Committing .env. Put it in .gitignore and share a .env.example instead.
  • Using export PORT=8080 in PowerShell. That is bash syntax. PowerShell uses $env:PORT = "8080".
  • Calling process.exit() too early. It can drop unwritten output. Set process.exitCode and let the program finish.

Key points

  • process describes the running program: version, platform, cwd(), memoryUsage() and more.
  • process.argv holds command-line arguments from index 2; parseArgs() from node:util parses options properly.
  • process.env holds environment variables; every value is a string or undefined.
  • node --env-file=.env app.js loads a .env file with no package; real environment variables take priority.
  • Check required settings at startup, keep .env out of Git, and prefer process.exitCode over process.exit().

Exercise

Write server-config.js that reads PORT (default 3000), SHOP_NAME (default "My Shop") and MAX_UPLOAD_MB (default 5) from the environment, converts the numbers, and prints them. Create a .env file that sets SHOP_NAME to Ananya Handlooms, Kochi and MAX_UPLOAD_MB to 10, then run the program with --env-file.

Show solution
JavaScript
// server-config.js
const config = {
  port: Number(process.env.PORT ?? 3000),
  shopName: process.env.SHOP_NAME ?? "My Shop",
  maxUploadMb: Number(process.env.MAX_UPLOAD_MB ?? 5),
};

console.log(config);
Terminal
# .env contains:
# SHOP_NAME="Ananya Handlooms, Kochi"
# MAX_UPLOAD_MB=10
node --env-file=.env server-config.js
Output
{ port: 3000, shopName: 'Ananya Handlooms, Kochi', maxUploadMb: 10 }

PORT is not in the file, so the default is used. The quotes in .env are removed when the file is loaded.

Quick Quiz

1. Your script is run as node app.js Pune. Where is "Pune"?

2. What type is process.env.PORT when it is set to 8080?

3. .env sets PORT=4000, and you run PORT=9000 node --env-file=.env app.js. Which port is used?

4. Why is process.exitCode = 1 usually better than process.exit(1)?

Learn Node.js with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call