JS Sketchbooksee JavaScript think ✏️
← back to phase 9

9.4 — process: argv, env & exit

How does the SAME test suite run against localhost on your machine, against staging — the team’s private practice copy of the site — in CI, and against the live site itself, without changing a line of code? Meet process: the object through which a Node program reads its own run — its command line, its environment, its exit.

This is where BASE_URL lives, where secrets hide, and where 9.2’s exit code gets set on purpose. Small lesson, permanent plumbing.

watch it happen
// greet.js
console.log(process.argv[2]);
//  $ node greet.js Lijas   →  Lijas

// check-env.js
const base = process.env.BASE_URL ?? "http://localhost:3000";
console.log(`testing against: ${base}`);

//  $ node check-env.js
//  →  testing against: http://localhost:3000
//  $ BASE_URL=https://staging.shop.com node check-env.js
//  →  testing against: https://staging.shop.com

if (!process.env.API_KEY) {
  console.error("missing API_KEY");
  process.exit(1);
}

In Node, one built-in global describes THIS very run of your program: process. Not the file, not the language — this execution, right now: what command started it, what environment surrounds it, how it will end. A program, introspecting itself.

process.argv — the command line as an array/usr/bin/node[0]/…/greet.js[1]"Lijas"[2][0] node itself · [1] the script · [2]+ YOUR inputsone global object describes THIS very run of your program: process — theprogram, introspecting itself
under the hood

The deeper story, with the real names for things — this part is what turns “I saw it” into “I can explain it.”

Everything in process.env is a string — always. PORT=3000 arrives as "3000", and CI=true arrives as "true" (the string!). The 1.9 coercion traps live here in the wild; real configs convert deliberately (Number(process.env.PORT), process.env.CI === "true").

Where do env vars come from? Layered sources: your shell session, the launch line itself (BASE_URL=… node app.js), CI pipeline settings, and — very commonly — a .env file loaded by a small library, with .env listed in .gitignore (8.2’s rule again: local, regenerable, never committed).

Honesty note on process.exit(): it’s an ejector seat — it ends the process immediately, without waiting for pending async work (6.x’s parked jobs are simply abandoned). Guard clauses at startup: perfect. Sprinkled mid-flight: a classic source of half-written files.

Job note: the convention CI=true is set by virtually every CI provider, and real Playwright configs read it to switch behavior — more retries and no headed browser on CI, for example. One env var, two worlds correctly served.

your turn

⌨️ the environment-driven script

Model a real suite’s startup: read an input from argv, aim at a target from env (with an honest default), and guard a required secret with an exit code.

requirements:

  • Model the run: argv as ["node", "greet.js", "Lijas"] and env as { BASE_URL: "https://staging.shop.com" }.
  • Print the user’s input — remember where inputs start in argv.
  • Write targetUrl(env) returning env.BASE_URL with the default "http://localhost:3000" when it’s absent (8.4’s honest default). Print it for env, then for an empty object.
  • Write guard(env) returning the exit code: 0 when BASE_URL is present, 1 when missing. Print it for both environments.

when you press RUN, the console must show exactly:

Lijas
https://staging.shop.com
http://localhost:3000
0
1

✏️ Quick check 1

You run: node greet.js Lijas — what is process.argv[2]?

✏️ Quick check 2

PORT=3000 arrives in process.env — what is typeof process.env.PORT?

✏️ Quick check 3

A startup guard finds a required secret missing and calls process.exit(1). What color does the CI pipeline turn?

teach it back

🗣️ Now teach it back

Explain to a friend how one test suite runs against localhost, staging, and production without code changes — covering argv, env vars (and where secrets live), and the exit-code guard pattern.

Write it as if your friend is sitting next to you. Saved to your journal — future-you will use these notes to teach others.

a few sentences, minimum — you’ve got this
to remember
process = this very run, introspected. argv = the command line as an array — YOUR inputs start at index 2. Everything in process.env is a STRING.
Env vars are settings from OUTSIDE the code: BASE_URL aims the suite; secrets are injected (never committed — git remembers forever). ?? supplies honest defaults.
process.exit(1) sets 9.2’s number on purpose — the startup guard pattern. console.error goes to stderr, a separate stream CI can split from normal output.
next: 9.5 The file system →