Path, OS & Process

1. Introduction 🧭

Beyond files themselves, Node scripts frequently need to reason about where they are running: file paths, the underlying operating system, and the current process. The path, os, and process modules provide exactly that — cross-platform utilities for portable, robust scripts.

2. Path Module 🛤️

The path module (node:path) provides utilities for working with file and directory paths consistently across operating systems — critical since Windows uses backslashes (\\) while POSIX systems use forward slashes (/).

path-import.js

const path = require('node:path');

3. Working with File Paths 📍

3.1 Absolute Paths

An absolute path specifies a location from the filesystem root, unambiguous regardless of the current working directory.

absolute-path.js

path.isAbsolute('/usr/local/bin'); // true (POSIX)
path.isAbsolute('C:\\Users\\dev'); // true (Windows)

3.2 Relative Paths

A relative path is resolved relative to the current working directory or another base path — e.g. ./config or ../lib/utils.js.

3.3 Path Normalization

path.normalize() cleans up a path string, resolving .. and . segments and collapsing redundant separators.

normalize.js

path.normalize('/users//dev/../dev/./app.js');
// => '/users/dev/app.js'

3.4 Joining Paths

path.join() combines multiple path segments using the platform-appropriate separator, then normalizes the result.

join.js

path.join('src', 'components', 'Button.tsx');
// => 'src/components/Button.tsx'

3.5 Resolving Paths

path.resolve() processes segments right to left, prepending each until an absolute path is constructed, defaulting to process.cwd() if no absolute segment is found.

resolve.js

path.resolve('src', 'index.js');
// => '/home/user/project/src/index.js' (absolute)

Important

path.join() is purely syntactic; path.resolve() always returns an absolute path.

3.6 Parsing Paths

parse.js

path.parse('/home/user/file.txt');
// => { root: '/', dir: '/home/user', base: 'file.txt', ext: '.txt', name: 'file' }

3.7 File Extensions

extname.js

path.extname('archive.tar.gz'); // '.gz'
path.basename('archive.tar.gz', '.gz'); // 'archive.tar'

4. OS Module 🖥️

The os module (node:os) exposes information about the underlying operating system and hardware the Node process is running on.

4.1 Operating System Information

os-info.js

const os = require('node:os');

console.log(os.platform()); // 'linux', 'darwin', 'win32'
console.log(os.type());     // 'Linux', 'Darwin', 'Windows_NT'
console.log(os.release());  // kernel/OS release version
console.log(os.arch());     // 'x64', 'arm64'

4.2 CPU Information

os-cpus.js

const os = require('node:os');

const cpus = os.cpus();
console.log(cpus.length, cpus[0].model, cpus[0].speed);

Tip

os.cpus().length is commonly used to decide how many worker_threads or cluster workers to spawn.

4.3 Memory Information

os-memory.js

const os = require('node:os');

console.log(os.totalmem()); // total system RAM in bytes
console.log(os.freemem());  // available RAM in bytes

4.4 Network Interfaces

os-network.js

const os = require('node:os');

console.log(os.networkInterfaces());
// { lo: [...], eth0: [...], wlan0: [...] }

4.5 User Information

os-user.js

const os = require('node:os');

console.log(os.userInfo());
// { username, uid, gid, shell, homedir }
console.log(os.homedir());
console.log(os.hostname());

5. Process Object ⚙️

process is a global object providing information about, and control over, the currently running Node.js process. Unlike path and os, it requires no require() call.

5.1 Process Lifecycle

Process Start
Load Entry Module
Execute Top-Level Code
Event Loop Runs Until Empty
Process Exit
Register Timers / Listeners / I/O

5.2 Command-Line Arguments

process.argv is an array where index 0 is the Node executable path, index 1 is the script path, and subsequent indices are user-supplied arguments.

argv-example.js

// node app.js --port 3000
const args = process.argv.slice(2);
console.log(args); // ['--port', '3000']

5.3 Environment Variables

env-example.js

console.log(process.env.NODE_ENV); // 'production', 'development', etc.
console.log(process.env.PORT || 3000);

Caution

Never hardcode secrets in source; read them from process.env, typically populated via a .env file and a package like dotenv.

5.4 Current Working Directory

cwd-example.js

console.log(process.cwd()); // directory the process was launched from
process.chdir('/tmp'); // change it

Information

process.cwd() is not the same as __dirname — the former depends on where you ran the command, the latter on where the file lives.

5.5 Process Events

process-events.js

process.on('exit', (code) => console.log('Exiting with code', code));
process.on('uncaughtException', (err) => console.error('Uncaught:', err));
process.on('unhandledRejection', (reason) => console.error('Unhandled rejection:', reason));

5.6 Exit Codes

CodeMeaning
0Success
1Uncaught fatal exception
130Terminated by SIGINT (Ctrl+C)

exit-code.js

if (!configValid) {
  console.error('Invalid config');
  process.exit(1);
}

5.7 Signals

Signals are OS-level notifications sent to a process, commonly used to trigger graceful shutdown.

signals.js

process.on('SIGTERM', () => {
  console.log('Received SIGTERM, shutting down gracefully...');
  server.close(() => process.exit(0));
});

process.on('SIGINT', () => {
  console.log('Received SIGINT (Ctrl+C)');
  process.exit(0);
});

6. Standard Streams 🔌

6.1 Standard Input

stdin-example.js

process.stdin.setEncoding('utf-8');
process.stdin.on('data', (chunk) => {
  console.log(`You typed: ${chunk.trim()}`);
});

6.2 Standard Output

stdout-example.js

process.stdout.write('Loading'); // no automatic newline, unlike console.log
process.stdout.write('...\n');

6.3 Standard Error

stderr-example.js

process.stderr.write('Error: something went wrong\n');

Tip

Write errors and diagnostics to stderr, and program output to stdout — this lets users redirect each stream independently (node app.js 1> out.log 2> err.log).

7. Performance Monitoring 📈

perf-monitoring.js

const usage = process.memoryUsage();
console.log(usage.heapUsed, usage.heapTotal, usage.rss);

const cpuUsage = process.cpuUsage();
console.log(cpuUsage.user, cpuUsage.system);

console.log(process.uptime()); // seconds since process start
MetricMeaning
rssTotal memory allocated for the process (Resident Set Size)
heapUsedMemory actively used by JS objects
heapTotalTotal heap memory allocated by V8

8. Best Practices ✅

  • Always use path.join()/path.resolve() instead of manually concatenating path strings.
  • Read configuration from process.env, never hardcode environment-specific values.
  • Handle SIGTERM/SIGINT for graceful shutdown in long-running servers.
  • Use os.cpus().length to size worker pools relative to available hardware.
  • Prefer explicit process.exitCode assignment over abrupt process.exit() where possible, to allow pending I/O to flush.

9. Common Mistakes ⚠️

  • Manually joining paths with string concatenation (dir + '/' + file), breaking on Windows.
  • Confusing __dirname with process.cwd().
  • Not handling unhandledRejection, letting silent Promise failures go unnoticed.
  • Calling process.exit() immediately after an async operation, cutting it off before completion.
  • Assuming environment variables are always strings of the expected type without parsing/validating them.

10. Frequently Asked Questions ❓

Question

What's the difference between path.join and path.resolve?

Answer

path.join() just concatenates and normalizes segments — it can return a relative path. path.resolve() always returns an absolute path, using process.cwd() as a base if needed.

Question

How do I read a password or secret input from the terminal?

Answer

Use process.stdin combined with a library like readline or a dedicated prompt package that can mask input — process.stdin alone doesn't hide typed characters.

Question

Why does my script behave differently when run from a different folder?

Answer

Likely because it relies on process.cwd() (which changes based on where you launch it) instead of __dirname (which is fixed to the file's location).

11. Summary 📝

Summary

The path module provides cross-platform utilities for building and parsing file paths, the os module exposes details about the underlying system (CPU, memory, network, user), and the global process object gives control over the current Node process — arguments, environment variables, signals, and standard streams. Mastering these three modules is essential for writing portable, production-ready CLI tools and servers.