process
The process object is a global available in all Node.js applications. It provides information about the current process and offers methods to control it. Unlike most modules that require an explicit import, process is available everywhere—you can access environment variables, command-line arguments, and termination methods directly.
This object is an instance of EventEmitter, so you can listen to process-level events like 'exit', 'uncaughtException', and 'SIGINT'.
Command-Line Arguments
process.argv
An array containing the command-line arguments passed when the Node.js process was launched. The first element is the path to the Node.js executable, the second is the path to the script being run, and the remaining elements are any additional arguments.
// Running: node app.js --version 1.0
console.log(process.argv);
// ['/usr/local/bin/node', '/path/to/app.js', '--version', '1.0']
process.argv0
process.argv0 is a read-only copy of the original argv[0] value. When a script modifies process.argv[0], this property retains the original executable name—useful for logging or diagnostics that need to report how the process was launched, not what the script later rewrote:
console.log(process.argv0);
// 'node' or whatever argv[0] was originally set to
process.execPath
While argv0 tells you the name used to launch the process, process.execPath gives you the full filesystem path to the Node.js binary that is actually running. This is the absolute path, resolved at startup, and it is the most reliable way to locate the Node.js installation directory at runtime:
console.log(process.execPath);
// '/usr/local/bin/node' on macOS/Linux
// 'C:\\Program Files\\nodejs\\node.exe' on Windows
Environment Information
The command-line tells you how the process was launched. Environment variables, by contrast, control how it behaves while running. The process object gives you direct read and write access to every environment variable visible to the process.
process.env
An object containing user environment variables. You can read and write to this object to modify environment variables for the current process.
// Read an environment variable
console.log(process.env.NODE_ENV);
// 'development' or 'production'
// Set a custom environment variable
process.env.MY_APP_SECRET = 'secret-key';
This property is particularly useful for configuring application behavior based on the environment. For example, you might enable verbose logging only when NODE_ENV !== 'production'.
process.platform
After configuring behavior with environment variables, you often need to know which operating system the code runs on. process.platform returns a short string identifying the OS—use this to branch on platform-specific logic like file paths, shell commands, or signal handling:
console.log(process.platform);
// 'linux', 'darwin', 'win32', 'freebsd', 'openbsd'
process.arch
The platform tells you which OS; the architecture tells you which CPU instruction set the binary targets. This matters when you distribute native addons or need to select architecture-specific binaries at install time. A mismatch here causes load failures, not compile errors, so checking early saves debugging later:
console.log(process.arch);
// 'x64', 'arm64', 'arm', 'ia32', 's390', etc.
process.version
Next, process.version gives you the Node.js version string in a compact format. This is the version you see in node --version, and it is the simplest way to check whether the runtime supports a feature you intend to use:
console.log(process.version);
// 'v22.10.0'
process.versions
For a more detailed view, process.versions exposes the version of every major dependency bundled with Node.js—V8, libuv, OpenSSL, zlib, and others. When you debug a crash that only happens on certain Node.js releases, checking the V8 or OpenSSL version through this object can narrow the problem faster than trial and error:
console.log(process.versions);
// {
// node: '22.10.0',
// v8: '12.8.344.25-node.6',
// uv: '1.120.0',
// zlib: '1.3.1',
// openssl: '3.0.15',
// ...
// }
Process Identification
Sometimes you just need to know who you are. The process ID and its parent are the most basic identifiers, useful for logging, creating lock files, or coordinating with a process supervisor. These two properties are the simplest way to answer “which process am I?“
process.pid
The process ID of the current process.
console.log(process.pid);
// 12345
process.ppid
The parent process ID is available through process.ppid. Knowing the parent PID is useful when a child process needs to monitor whether its parent is still alive, or when a process manager wants to trace the process tree for debugging or resource accounting:
console.log(process.ppid);
// 67890
Working Directory
Every process has a current working directory that anchors all relative path resolutions. The two methods below let you inspect and change it. Knowing the working directory is essential when your application reads configuration files or writes output relative to its launch location.
process.cwd()
Returns the current working directory of the Node.js process.
console.log(process.cwd());
// '/home/user/project'
process.chdir(directory)
Once you know the current directory, you can change it with process.chdir(). This alters the working directory for the entire process, which affects all relative path resolutions going forward. Be cautious—changing the directory in one part of your program changes it everywhere. Always wrap the call in a try/catch, since the target directory might not exist or might lack read permissions:
console.log(`Starting directory: ${process.cwd()}`);
try {
process.chdir('/tmp');
console.log(`New directory: ${process.cwd()}`);
} catch (err) {
console.error(`Failed to change directory: ${err}`);
}
Exiting and Terminating
Knowing the working directory is one half of process control; deciding when and how to stop is the other. The following methods give you several ways to end the process, each with a different level of abruptness. Choose the one that matches your shutdown strategy—graceful termination, immediate abort, or an exit code set in advance.
process.exit([code])
Terminates the process with the specified exit code. Omitting the code or passing 0 indicates successful termination. Passing a non-zero value indicates error conditions.
// Exit with success code
process.exit(0);
// Exit with error code
process.exit(1);
// Exit with custom error code
process.exit(42);
process.exitCode
Calling process.exit() stops execution immediately—any pending I/O or timers are dropped. For a softer exit, set process.exitCode instead. The process will exit naturally when the event loop drains, using the code you assigned. This approach lets in-flight operations finish before the process terminates:
process.exitCode = 1;
// When the process exits naturally, it will use code 1
process.abort()
If you need the most abrupt termination possible—for example, when the process is in an unrecoverable state—process.abort() kills it immediately and, on supported platforms, writes a core dump. Core dumps let you inspect the process memory with a debugger like lldb or gdb, but the file can be large and the termination is not graceful. Avoid this in production unless you have a core dump pipeline in place:
process.abort();
// Generates a core file and terminates
process.kill(pid[, signal])
While the previous methods control the current process, process.kill() sends a signal to another process by its PID. Despite the name, kill does not always terminate—you can send any POSIX signal, including 0 to test whether a process exists without affecting it:
// Send SIGTERM to a process
process.kill(12345);
// Send a specific signal
process.kill(12345, 'SIGKILL');
// Send signal 0 to check if process exists (doesn't actually kill it)
try {
process.kill(12345, 0);
console.log('Process exists');
} catch (err) {
console.log('Process does not exist');
}
Memory and CPU Usage
Once your process is running, you need visibility into its resource consumption. The next three methods cover memory, CPU, and broader OS-level usage—the triad you reach for when diagnosing a slow or bloated Node.js application. Each answers a different diagnostic question.
process.memoryUsage()
Returns an object describing memory usage of the Node.js process.
console.log(process.memoryUsage());
// {
// rss: 25645056,
// heapTotal: 4894712,
// heapUsed: 2763656,
// external: 245760,
// arrayBuffers: 11936
// }
rss(Resident Set Size): Total memory allocated by the processheapTotalandheapUsed: V8 heap memoryexternal: Memory used by native addons
process.cpuUsage([previousValue])
Memory is one dimension of resource consumption. process.cpuUsage() measures how much CPU time the process has used, broken into user and system time. Call it once to get a baseline, then call it again later and pass the previous value as an argument to get a delta—this tells you how much CPU a specific operation consumed:
const start = process.cpuUsage();
// { user: 1000, system: 500 }
// ... your code runs here ...
const end = process.cpuUsage(start);
// { user: 2500, system: 800 }
process.resourceUsage()
Beyond CPU and memory, process.resourceUsage() reports broader OS-level metrics—filesystem I/O counts, context switches, and network socket activity. This data is most valuable when you suspect a resource leak that is not visible in heap snapshots or CPU profiles alone:
console.log(process.resourceUsage());
// {
// userCPUUsage: 12345,
// systemCPUUsage: 6789,
// maxRSS: 45678,
// sharedMemorySize: -1,
// ...
// }
Time and Timing
Resource metrics tell you what the process consumed. Time metrics tell you when and how long things took. The following three methods cover wall-clock uptime, high-resolution elapsed measurement, and event-loop scheduling—each answers a different question about time inside the runtime.
process.uptime()
Returns the number of seconds the current Node.js process has been running.
console.log(`Process uptime: ${process.uptime()} seconds`);
// Process uptime: 3600 seconds
process.hrtime([time])
process.uptime() tells you how long the process has been alive. For high-precision measurement of a specific code path, use process.hrtime() instead. It returns a [seconds, nanoseconds] tuple with sub-millisecond resolution. Call it before and after the operation you want to measure, then subtract the tuples to get elapsed time:
const start = process.hrtime();
// ... code being timed ...
const diff = process.hrtime(start);
console.log(`Took ${diff[0] * 1000 + diff[1] / 1000000} milliseconds`);
process.nextTick(callback)
Timing in Node.js is not just about wall-clock measurement. process.nextTick() schedules a callback to run at the very end of the current operation, before any I/O or timers fire. It has the highest priority in the event loop, which means you can use it to defer work without yielding to pending I/O. The tradeoff is that recursive nextTick calls can starve the event loop, so use it sparingly:
console.log('Start');
process.nextTick(() => {
console.log('Next tick');
});
console.log('End');
// Output: Start, End, Next tick
Error handling events
The object emits several events related to error handling. Attaching a listener to uncaughtException is the last line of defense before a crash, while unhandledRejection catches promises that would otherwise fail silently. Both should log the error and perform a controlled shutdown rather than attempt recovery, since the process state may be corrupted:
process.on('uncaughtException', (err, origin) => {
console.error(`Uncaught exception: ${err.message}`);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error(`Unhandled rejection at: ${promise}, reason: ${reason}`);
});
Standard Streams
Error handling keeps the process alive when things go wrong. When things are working, you communicate through standard streams—stdin for input, stdout for output, and stderr for diagnostics. These three streams are the fundamental I/O channels that every Unix process inherits, and Node.js exposes them directly on the process object.
process.stdin, process.stdout, process.stderr
Standard input, output, and error streams. These are Stream objects that can be used for reading input or writing output.
// Reading from stdin
process.stdin.setEncoding('utf8');
process.stdin.on('data', (chunk) => {
console.log(`Received: ${chunk}`);
});
// Writing to stdout
process.stdout.write('Hello, world!\n');
// Writing to stderr
process.stderr.write('Error occurred!\n');
Process Events
Error handling and standard streams cover the data path. The process also emits lifecycle and signal events that let you hook into the runtime itself. These are the hooks you reach for when implementing graceful shutdown, crash recovery, or custom signal handling logic.
Signal Events
Beyond error conditions, the process also responds to operating system signals. These let external tools (or the terminal) communicate with your application. Handling SIGINT and SIGTERM is the standard way to implement a graceful shutdown that closes database connections and flushes pending writes before the process exits:
// Handle SIGINT (Ctrl+C)
process.on('SIGINT', () => {
console.log('Received SIGINT, shutting down gracefully');
process.exit(0);
});
// Handle SIGTERM
process.on('SIGTERM', () => {
console.log('Received SIGTERM, shutting down');
process.exit(0);
});
Common signals:
SIGINT: Interrupt from terminal (Ctrl+C)SIGTERM: Termination requestSIGKILL: Immediate termination (cannot be caught)
Common Patterns
The individual APIs are building blocks. Real applications combine them into patterns that solve everyday problems. Here are three patterns you will reach for in nearly every Node.js project—graceful shutdown, environment-driven configuration, and high-resolution performance measurement.
Graceful Shutdown
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
function shutdown() {
console.log('Shutting down...');
// Clean up resources
process.exit(0);
}
Environment-Based Configuration
The shutdown pattern shows how to react to external signals. Another common pattern uses environment variables to configure behavior at startup. Checking NODE_ENV is the simplest way to toggle development-only features like verbose logging or hot reloading without changing any code:
const isProduction = process.env.NODE_ENV === 'production';
if (isProduction) {
console.log('Running in production mode');
} else {
console.log('Running in development mode');
}
Measuring execution time
When configuration is set and the app is running, you may want to measure how long a particular function takes. process.hrtime.bigint() returns a high-resolution timestamp as a BigInt, which is cleaner for subtraction than the tuple form. Subtract the start value from the end value and divide by one million to get milliseconds:
const start = process.hrtime.bigint();
// Your code here
const result = heavyComputation();
const end = process.hrtime.bigint();
console.log(`Execution took ${(end - start) / 1000000n}ms`);
See Also
- os module — operating system utility methods
- path module — path manipulation utilities
- events module — event emitter implementation
- child_process module — spawning and managing sub-processes