Browse packages

Package · v0.18.0

runtime

Standard library runtime environment

Runtime detection for JavaScript environments.

What is @rcompat/runtime?#

A cross-runtime module that tells you which JavaScript runtime your code is executing in, and provides runtime-specific utilities like the executable path, current script, arguments, and process exit. Uses runtime keys for accurate detection without any runtime overhead.

Installation#

bash
npm install @rcompat/runtime
bash
pnpm add @rcompat/runtime
bash
yarn add @rcompat/runtime
bash
bun add @rcompat/runtime

Usage#

Basic detection#

js
import runtime from "@rcompat/runtime";

console.log(runtime.name);
// "node" | "bun" | "deno" | "browser"

Conditional logic#

js
import runtime from "@rcompat/runtime";

if (runtime.name === "bun") {
  // Bun-specific code
} else if (runtime.name === "deno") {
  // Deno-specific code
} else if (runtime.name === "node") {
  // Node.js-specific code
}

Executable path#

js
import runtime from "@rcompat/runtime";

console.log(runtime.bin);
// "/usr/local/bin/node"
// "/home/user/.bun/bin/bun"
// "/usr/bin/deno"

Current script#

js
import runtime from "@rcompat/runtime";

console.log(runtime.script);
// "/path/to/your/script.js"

Program arguments#

js
import runtime from "@rcompat/runtime";

// running: node app.js foo bar
console.log(runtime.args);
// ["foo", "bar"]

runtime.args always contains only your program's arguments — the runtime executable and script path are stripped away, consistently across all runtimes.

Exiting the process#

js
import runtime from "@rcompat/runtime";

runtime.exit(0);  // success
runtime.exit(1);  // failure

In browsers, process operations such as exit, cwd, and resolve throw an unimplemented error.

Process memory usage#

js
const usage = runtime.memoryUsage();

if (usage) {
  console.log(usage.rss);
  console.log(usage.heapUsed);
}

runtime.memoryUsage() returns an instantaneous aggregate process-memory sample. Every available value is measured in bytes. It does not trigger garbage collection, enable an inspector or profiler, retain sample history, or start background sampling.

Node and Bun provide all fields. Deno does not expose arrayBuffers through its native aggregate API, so that field is undefined. Browsers return undefined because there is no portable browser API with equivalent process memory categories. In particular, this package does not use the non-standard Chromium-only performance.memory API.

Supported Runtimes#

Runtime Value
Node.js "node"
Bun "bun"
Deno "deno"
Browser "browser"

API Reference#

The runtime contract and supporting types are available as type-only exports:

ts
import type { Flags, MemoryUsage, Resolve, Runtime } from "@rcompat/runtime";

runtime.name#

ts
runtime.name: string;

A string identifying the current runtime environment.

runtime.bin#

ts
runtime.bin: string;

Full path to the runtime executable. This is an empty string in browsers.

runtime.script#

ts
runtime.script: string;

Full path to the currently executing script. This is an empty string in browsers.

runtime.args#

ts
runtime.args: string[];

Program arguments, with the runtime executable and script path stripped. Always an array—empty if no arguments were passed, and [] in browsers.

runtime.exit#

ts
runtime.exit(code?: number): never;

Exit the current process with an optional exit code. This throws in browsers, where process exit has no meaning.

runtime.memoryUsage()#

ts
interface MemoryUsage {
  readonly rss: number | undefined;
  readonly heapTotal: number | undefined;
  readonly heapUsed: number | undefined;
  readonly external: number | undefined;
  readonly arrayBuffers: number | undefined;
}

runtime.memoryUsage(): MemoryUsage | undefined;

Returns aggregate resident-set, JavaScript heap, external, and ArrayBuffer memory in bytes. An unavailable field is undefined, preserving the difference between an unsupported metric and a real zero value. The whole result is undefined when the runtime cannot provide a portable aggregate sample.

runtime.resolve#

ts
runtime.resolve(specifier: string, from: string): string

Resolve a path or package specifier from a directory.

  • Relative specifiers like ./foo.json and ../tsconfig.json are resolved from from
  • Absolute paths are returned as absolute paths
  • Package specifiers like apekit/tsconfig are resolved using the current runtime’s package resolution

Filesystem and package helpers#

ts
runtime.cwd(): FileRef;
runtime.projectRoot(from?: Path): Promise<FileRef>;
runtime.packageJSON(from?: Path): Promise<PackageJSON>;
runtime.conditions(from?: Path): Promise<string[]>;

cwd returns the current working directory. projectRoot walks upward to the nearest package.json, packageJSON reads that manifest, and conditions collects and deduplicates active --conditions flags and inherited tsconfig.json custom conditions. Circular tsconfig extension chains throw.

Platform information#

runtime.os is "linux", "darwin", "windows", or undefined when the platform is unavailable. runtime.arch is "x64", "arm64", or undefined.

How It Works#

This package uses runtime keys, a WinterCG proposal for runtime detection. The exports field in package.json routes to different files based on the runtime condition, meaning detection happens at import time with zero runtime overhead.

json
{
  "exports": {
    ".": {
      "bun": "./lib/public/bun.js",
      "deno": "./lib/public/deno.js",
      "browser": "./lib/public/browser.js",
      "node": "./lib/public/node.js"
    }
  }
}

Each file simply exports the runtime object for that environment:

ts
// node.ts
export default {
  name: "node",
  bin: process.execPath,
  script: process.argv[1],
  args: process.argv.slice(2),
  exit: (code?: number) => process.exit(code),
};

Examples#

Relaunching with custom flags#

js
import runtime from "@rcompat/runtime";
import io from "@rcompat/io";

// relaunch self with --conditions=source
const child = io.spawn(runtime.bin, [
  "--conditions=@rcompat/source",
  runtime.script,
  ...runtime.args,
], { stdio: "inherit" });

const status = await child.status;
runtime.exit(status.code ?? 1);

Runtime-specific logging#

js
import runtime from "@rcompat/runtime";

const logger = {
  info(message) {
    console.log(`[${runtime.name}]`, message);
  }
};

logger.info("Server started");
// [node] Server started
// [bun] Server started

Environment checks#

js
import runtime from "@rcompat/runtime";

const isServerRuntime = ["node", "bun", "deno"].includes(runtime.name);
const isClientRuntime = runtime.name === "browser";

Debug information#

js
import runtime from "@rcompat/runtime";

function getDebugInfo() {
  return {
    runtime: runtime.name,
    script: runtime.script,
    args: runtime.args,
    timestamp: Date.now(),
  };
}

Reading active conditions#

ts
import runtime from "@rcompat/runtime";

const conditions = await runtime.conditions();

Cross-Runtime Compatibility#

Runtime Supported
Node.js ✓
Bun ✓
Deno ✓
Browser ✓

No configuration required — just import and use.

License#

MIT

Contributing#

See CONTRIBUTING.md in the repository root.