🌱BeginnerNode.js Foundations

The process Object

Control and inspect the running Node.js process with the global process object

Overview

The `process` object is a global in Node.js β€” you can use it anywhere without requiring it. It provides information about and control over the currently running Node.js process, which makes it essential for writing CLI tools, servers, and any application that needs to respond to its environment or handle shutdown gracefully. The most frequently used properties are `process.argv` (command-line arguments), `process.env` (environment variables, covered in the previous topic), `process.cwd()` (current working directory), `process.pid` (process ID), and `process.version` (Node version string). These are read-only windows into the process's identity and context. For control, `process.exit(code)` terminates the process immediately with an exit code β€” 0 means success, any non-zero value signals an error. This is how CLI tools communicate success or failure to the shell. Be careful with `process.exit()` in servers: it bypasses async cleanup, so prefer graceful shutdown patterns where you close connections first. The process object is also an event emitter. The most important events are `exit` (fires synchronously when the process is about to exit β€” only synchronous code runs here), `uncaughtException` (an unhandled error would otherwise crash the process), and `SIGTERM` / `SIGINT` (signals from the OS or Ctrl+C) which are where you implement graceful shutdown β€” draining connections and flushing buffers before exiting.

Key Points

  • β€’process is a global β€” no require() needed
  • β€’process.argv is an array: [node-path, script-path, ...user-args]; user args start at index 2
  • β€’process.cwd() returns the directory from which Node was launched (different from __dirname)
  • β€’process.exit(0) means success; process.exit(1) or any non-zero means error
  • β€’process.on("SIGTERM") and process.on("SIGINT") let you implement graceful shutdown
  • β€’process.stdout and process.stderr are writable streams β€” used by console.log/error internally

Examples

Reading command-line arguments from process.argv

// Run as: node script.js hello world --flag
console.log(process.argv);
// ['/path/to/node', '/path/to/script.js', 'hello', 'world', '--flag']

// User-supplied args start at index 2
const args = process.argv.slice(2);
console.log(args); // ['hello', 'world', '--flag']

// Simple flag parser
const verbose = args.includes('--verbose');
const name    = args.find(a => !a.startsWith('--')) ?? 'World';
console.log(`Hello ${name}! Verbose: ${verbose}`);

Process identity and environment info

console.log('PID:', process.pid);
console.log('Node version:', process.version);
console.log('Platform:', process.platform);
console.log('cwd:', process.cwd());
console.log('uptime (s):', process.uptime());
console.log('memory usage:', process.memoryUsage());
// { rss, heapTotal, heapUsed, external, arrayBuffers }

process.memoryUsage() returns values in bytes. heapUsed is how much V8 heap your JS objects consume.

Graceful shutdown on SIGTERM and SIGINT

const http = require('http');

const server = http.createServer((req, res) => res.end('OK'));
server.listen(3000);

function shutdown(signal) {
  console.log(`Received ${signal}, shutting down gracefully...`);
  server.close(() => {
    console.log('All connections closed. Exiting.');
    process.exit(0);
  });
  // Force exit after 10 seconds if connections don't drain
  setTimeout(() => process.exit(1), 10_000).unref();
}

process.on('SIGTERM', () => shutdown('SIGTERM')); // Kubernetes/Docker stop
process.on('SIGINT',  () => shutdown('SIGINT'));  // Ctrl+C

.unref() on the timeout prevents it from keeping the process alive if connections close quickly.

Catching uncaught exceptions and unhandled rejections

// Last-resort error handlers β€” log and exit cleanly
process.on('uncaughtException', (err) => {
  console.error('UNCAUGHT EXCEPTION:', err);
  process.exit(1); // always exit after uncaught exception
});

process.on('unhandledRejection', (reason) => {
  console.error('UNHANDLED REJECTION:', reason);
  process.exit(1);
});

// These should be a safety net, not a replacement for try/catch

The Node.js docs strongly recommend exiting after uncaughtException β€” the process may be in an undefined state.

Common Mistakes

  • Accessing process.argv[0] or [1] expecting user input β€” those are the node executable and script paths; user args start at index 2
  • Using process.exit() in the middle of an HTTP request handler without closing the server first β€” this drops active connections abruptly
  • Using uncaughtException as a general error suppressor instead of a last-resort logger β€” unhandled errors indicate bugs, not expected conditions
  • Confusing process.cwd() with __dirname β€” cwd is where Node was launched, __dirname is where the source file lives

Note

Use `process.exitCode = 1` instead of `process.exit(1)` in long-lived processes. Setting exitCode defers the exit code until the process exits naturally, allowing async cleanup to finish β€” whereas process.exit() is immediate and skips pending callbacks.

Exercises

Write Node.js code in your local terminal. Use the editor below to follow along, then mark each exercise as done once it works.

Loading editor…

Completed: 0 / 6 exercises

Knowledge Check

Question 1 of 4

Given the command `node script.js foo bar`, what does process.argv[2] contain?