Skip to content

path and process

Two built-in features you’ll use in almost every Node.js project: the path module for working with file system paths, and the process global for runtime information.

File paths look different on Windows (C:\Users\alice\file.txt) and Unix (/home/alice/file.txt). The path module handles this automatically.

import { join, resolve, dirname, basename, extname } from 'path'

Joins path segments with the correct separator for the OS:

import { join } from 'path'
const dbPath = join(process.cwd(), 'data', 'bulletin.db')
// Unix: '/home/user/project/data/bulletin.db'
// Windows: 'C:\Users\user\project\data\bulletin.db'

Always use path.join instead of string concatenation for paths.

Resolves a sequence of paths into an absolute path, starting from the current working directory:

import { resolve } from 'path'
resolve('src', 'index.ts')
// → '/absolute/path/to/project/src/index.ts'
import { dirname, basename, extname } from 'path'
const filePath = '/home/alice/project/src/index.ts'
dirname(filePath) // '/home/alice/project/src'
basename(filePath) // 'index.ts'
extname(filePath) // '.ts'
basename(filePath, extname(filePath)) // 'index' (name without extension)

process is a global available in every Node.js file — no import needed. It provides information about the running process.

The current working directory — the directory from which you ran node:

console.log(process.cwd())
// → '/home/user/bulletin-api'

Use this to build absolute paths that work regardless of where you require/import from:

const dbPath = join(process.cwd(), 'bulletin.db')

A dictionary of environment variables. This is how configuration values (database paths, JWT secrets, ports) are passed to Node.js without hardcoding them:

const port = process.env.PORT || '3000'
const jwtSecret = process.env.JWT_SECRET
if (!jwtSecret) {
throw new Error('JWT_SECRET environment variable is required')
}

Command-line arguments passed to the script:

// node script.ts --migrate --seed
console.log(process.argv)
// ['node', '/path/to/script.ts', '--migrate', '--seed']

Useful for build scripts and migration utilities.

Exits the Node.js process with a status code:

process.exit(0) // success
process.exit(1) // error (non-zero = failure for CI/CD)

Handle unexpected errors that weren’t caught anywhere:

process.on('uncaughtException', (error) => {
console.error('Uncaught exception:', error)
process.exit(1)
})

In production, use a proper error monitoring service — but this prevents silent crashes during development.

The API uses path and process throughout:

src/db/index.ts
import { join } from 'path'
import Database from 'better-sqlite3'
const dbPath = process.env.DATABASE_PATH || join(process.cwd(), 'bulletin.db')
const db = new Database(dbPath)
src/index.ts
const PORT = parseInt(process.env.PORT || '3000', 10)
app.listen(PORT, () => console.log(`API running on port ${PORT}`))
  1. Create src/utils/paths.ts that exports a paths object with absolute paths for common project directories: root, src, db.
  2. Use process.cwd() and path.join to build these.
  3. Log the paths and verify they’re correct absolute paths.
  4. Add a check: if process.env.NODE_ENV isn’t set, log a warning.
  • path.join(...) builds cross-platform paths — always use it instead of string concatenation.
  • path.resolve(...) creates absolute paths from the current directory.
  • process.cwd() is the directory from which the script was run.
  • process.env holds environment variables — use it for configuration.
  • process.argv has command-line arguments; process.exit(code) terminates the process.