Process & Env

runtime:process gives you the environment, CLI arguments, working directory, signals, and exit.

It is an ES module, gated on the Env capability — except the signal exports, which need Signals, and platform, arch, exit, and permissions, which need none. Import only what you need.

Reading process info

env is a plain object; args is the script's own arguments.

JavaScript
import { env, args, cwd } from "runtime:process";

console.log(cwd());     // "/srv/app"
console.log(args);      // ["build", "--watch"]
console.log(env.HOME);  // "/home/app"
In-process only

Writing or deleting an env key changes it for this run only — it never touches the host or child processes.

Environment files

Load variables from a .env file with --env-file.

Shell
# .env
DATABASE_URL=postgres://localhost/app
PORT=8080
API_TOKEN=tok_live_123
Shell
esrun --env-file=.env app.js

# Let the file beat the OS environment (default: OS wins):
esrun --env-file=.env --env-override app.js
No auto-loading

A .env is read only when you pass --env-file. Nothing on disk is loaded implicitly from the working directory.

Precedence

The OS environment wins on a conflict by default, so a committed .env can't clobber production config. Pass --env-override to flip it.

One file

A single --env-file is supported — production config comes from one .env or the orchestrator. There is no .env.* layering.

Secrets are masked

Secret-bearing keys are wrapped so they print as [redacted] in logs, strings, and JSON.

A key qualifies if it ends in _KEY, _TOKEN, _SECRET, _PASS(WORD), or contains CREDENTIAL/AUTH.

JavaScript
import { env, unmask } from "runtime:process";

console.log(env.API_TOKEN);        // [redacted]
console.log(`${env.API_TOKEN}`);   // [redacted]
JSON.stringify(env);               // ..."API_TOKEN":"[redacted]"...

const token = unmask(env.API_TOKEN); // real value, explicit
Reading a secret

Call unmask(value) to get the real string. Plain values pass through, so unmask(env.ANY) is always safe.

Masking is for accidents, not attackers

It stops secrets leaking into logs by mistake. It is not a sandbox — code you run can call unmask itself.

Signals

Watching a signal suppresses its default action — that is how a graceful shutdown is written, and why it needs its own Signals capability.

JavaScript
import { onSignal, offSignal } from "runtime:process";
import { serve } from "runtime:http";

const server = serve(handler);

const shutdown = async (signal) => {
  offSignal(signal, shutdown);   // a second ^C should kill, not queue
  await server.stop();           // stop accepting, drain in-flight
  await pool.close();
};
onSignal("SIGINT", shutdown);
onSignal("SIGTERM", shutdown);
PlatformDeliverable
UnixSIGINT, SIGTERM, SIGHUP, SIGUSR1, SIGUSR2
WindowsSIGINT, SIGBREAK

signals() reports the set. Asking for one the platform cannot deliver throws, rather than registering a handler that would never fire.

A watch keeps the program alive

While anything is watched the program stays running to receive it, as in Node and Deno. Removing the last handler releases it. Repeated deliveries coalesce: a burst of SIGHUPs arrives once.

Permissions

permissions reports what this run may reach. The policy is fixed at launch by esrun's denial flags, so has() is a synchronous boolean — there is nothing to request.

JavaScript
import { permissions } from "runtime:process";

permissions.denied; // ["read", "write"]
permissions.has("net"); // true

if (permissions.has("write")) await fs.write("cache.json", data);

Names: read, write, imports, net, listen, env, run, signals — the same words the --deny-<name> and --allow-<name> flags take. Any other name throws a TypeError.

A scoped grant answers true: under --allow-env=PORT you may read an environment variable, and the ones outside the list are simply absent. has() reports whether the capability is granted, not whether a particular value is in its list — and there is no second argument for asking about one (has("read", "/etc/passwd") throws). Scoping is the deployment's business; to find out about one value, do the thing and catch ERR_PERMISSION_DENIED.

Exit

exit(code) records the status and halts immediately — nothing after it runs.

Full export list and types: runtime:process API reference. CLI flags: esrun CLI.

Last updated on
Edit this page