---
title: 'The Process Object'
source: 'https://academia.sh/en/courses/nodejs/process-object'
course: 'The Node.js Runtime'
language: en
updated: '2026-08-17T18:09:52+00:00'
license: 'CC BY-SA 4.0'
---

# The Process Object

The argument array, environment variables, the object counterpart of the standard streams, the two ways to set an exit code, and the exit hook.

The previous lesson examined the loop's turns. The program running inside those turns
talks to the outside world not only through files and the network but also with the
environment that started it: what arguments was it called with, which environment
variables did it inherit, where is its output connected, and what will it report to
its caller when it ends?

All of this is gathered in a single global object. What a shell script did with `$1`,
`$?`, and `$HOME` in the Shell Programming course, this object's fields do here.

## Arguments and Environment

`process.argv` carries the command line the process was started with, as an array of
strings. The array's first two elements are fixed: the executable's path and the
running main module's path. The arguments the user typed start at the third element.

```js
// process-info.mjs
console.log('argv[0] last part:', process.argv[0].split('/').pop());
console.log('argv[1] last part:', process.argv[1].split('/').pop());
console.log('remaining args   :', process.argv.slice(2));
console.log('platform         :', process.platform);
console.log('working dir      :', process.cwd().split('/').pop());
console.log('MEASUREMENTS_DIR :', process.env.MEASUREMENTS_DIR ?? '(undefined)');
```

```sh
node process-info.mjs --node edge-01 --format summary
```

```
argv[0] last part: node
argv[1] last part: process-info.mjs
remaining args   : [ '--node', 'edge-01', '--format', 'summary' ]
platform         : darwin
working dir      : lab
MEASUREMENTS_DIR : (undefined)
```

The full paths on the first two lines vary by machine, so the example prints only
their last parts. `platform` gives a different value per operating system;
`working dir` depends on which directory you called the command from. The next topic
covers the right way to pin paths down.

Environment variables are read through `process.env`. Every value is a string; if you
expect a number, converting and validating it is on you.

```sh
MEASUREMENTS_DIR=/data/measurements node process-info.mjs
```

```
argv[0] last part: node
argv[1] last part: process-info.mjs
remaining args   : []
platform         : darwin
working dir      : lab
MEASUREMENTS_DIR : /data/measurements
```

Writing the variable before the command defines it only for that call; the shell
session is unaffected — the same environment-inheritance rule from the Shell
Programming course.

## The Object Counterpart of the Standard Streams

In the Shell Programming course, the three standard streams were referred to by
number: 0 input, 1 output, 2 error. The runtime offers these three as objects:
`process.stdin`, `process.stdout`, `process.stderr`. Not ordinary objects but stream
objects, detailed in later lessons; for now, their `write` methods are enough.

The stream-separation rule holds here too: data goes to standard output, every
description about it goes to standard error. The tool below reads the measurement
file and prints two tab-separated columns; the counter and error messages go to the
second stream.

```js
// stream-separation.mjs
import { readFileSync } from 'node:fs';

const file = process.argv[2] ?? 'measurements.ndjson';

let text;
try {
  text = readFileSync(file, 'utf8');
} catch (error) {
  process.stderr.write(`error: could not read ${file} (${error.code})\n`);
  process.exitCode = 66;                    // no data input
  text = '';
}

let count = 0;
for (const line of text.split('\n')) {
  if (line.trim() === '') continue;
  const { node, value } = JSON.parse(line);
  process.stdout.write(`${node}\t${value}\n`);
  count += 1;
}

process.stderr.write(`${count} records processed\n`);

process.on('exit', (code) => {
  process.stderr.write(`process exiting with code ${code}\n`);
});
```

To see only the data, the second stream is discarded:

```sh
node stream-separation.mjs 2>/dev/null | head -3
```

```
edge-01	21.4
edge-01	48
edge-02	19.8
```

To see only the diagnostic messages, the first stream:

```sh
node stream-separation.mjs 1>/dev/null
```

```
12 records processed
process exiting with code 0
```

This separation is the precondition for the tool to be pluggable into a pipeline. If
the counter line went to standard output, the next command reading that output would
mistake it for a data line.

`console.log` writes to standard output, `console.error` to standard error. Both are
convenience functions built on `write`; formatting objects readably is useful, but
where the output feeds another program, `write` is preferred for controlling the
format directly.

## Exit Code

The only numeric result a process reports to its caller is the exit code. The rule
from the Shell Programming course holds here too: zero means success, any nonzero
value is a kind of failure.

There are two ways to set the code, and the difference between them matters.

```js
// exit-hard.mjs
setTimeout(() => console.log('pending work'), 0);
console.log('before exit');
process.exit(3);
```

```sh
node exit-hard.mjs; echo "exit code: $?"
```

```
before exit
exit code: 3
```

```js
// exit-soft.mjs
setTimeout(() => console.log('pending work'), 0);
console.log('before exit');
process.exitCode = 3;
```

```sh
node exit-soft.mjs; echo "exit code: $?"
```

```
before exit
pending work
exit code: 3
```

`process.exit` stops the event loop right then; queued callbacks never run — the
absence of `pending work` in the first output above is the result. The same
interruption can apply to output not yet flushed: in a process whose output is
connected to a file or pipe, the write can run asynchronously, and a hard exit can
cut it off midway.

Writing to `process.exitCode`, though, only records the result. The process ends with
this code once the loop finishes its work and empties naturally. A pending write, a
closing connection, and an ongoing file operation get to complete.

The rule: **a hard exit is used only when the process's state is judged to be
corrupted.** On ordinary error paths, the code is written to the field and the
process ends on its own.

The tool above follows this rule. When the file is not found, the process is given
code 66, but it is not cut short; the counter line and the exit hook still run:

```sh
node stream-separation.mjs missing.ndjson; echo "exit code: $?"
```

```
error: could not read missing.ndjson (ENOENT)
0 records processed
process exiting with code 66
exit code: 66
```

## The Exit Hook

The callback set up with `process.on('exit', ...)` runs right before the process
ends and takes the exit code as its argument — what wrote the last line in both runs
above.

This hook has one strict rule: **asynchronous work cannot be started inside it.** The
process is about to close; the loop is never returned to after the hook, so a timer
or file write set up inside it never runs. The hook is only for short, synchronous
work — writing a counter, releasing a lock, that sort of thing.

Real cleanup work is done when a shutdown **signal** is received; signals and
graceful shutdown are the subject of the Process Management and Robustness lesson.

Two more fields describe the process itself. `process.pid` is the identifier the
operating system gives it, different on every run, used to tell processes apart in
log lines. `process.uptime()` gives the seconds since the process started, written as
age information at health probes.

## Summary

- The first two elements of `process.argv` are the executable and main-module
  paths; user arguments start at the third element.
- `process.env` values are always strings; numeric or boolean interpretation is the
  reading code's responsibility.
- The three standard streams are offered as objects; a tool becomes pluggable into
  a pipeline once data goes to standard output and diagnostics go to standard
  error.
- `process.exit` cuts the loop right then and drops pending work; `process.exitCode`
  only records the result and lets the process end naturally.
- The `exit` hook is suited only to synchronous work; since the event loop is never
  returned to after it, asynchronous cleanup cannot be done there.

## Next Step

In this lesson, the file name was given as `measurements.ndjson`, relative to the
working directory; the program cannot find it when called from another directory. The
next lesson takes up the mechanism that removes this dependency: the rules the
runtime uses to decide which file to load when a name is written — the distinction
between a built-in module, a file path, and a package name.
