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#
npm install @rcompat/runtimepnpm add @rcompat/runtimeyarn add @rcompat/runtimebun add @rcompat/runtimeUsage#
Basic detection#
import runtime from "@rcompat/runtime";
console.log(runtime.name);
// "node" | "bun" | "deno" | "browser"Conditional logic#
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#
import runtime from "@rcompat/runtime";
console.log(runtime.bin);
// "/usr/local/bin/node"
// "/home/user/.bun/bin/bun"
// "/usr/bin/deno"Current script#
import runtime from "@rcompat/runtime";
console.log(runtime.script);
// "/path/to/your/script.js"Program arguments#
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#
import runtime from "@rcompat/runtime";
runtime.exit(0); // success
runtime.exit(1); // failureIn browsers, process operations such as exit, cwd, and resolve throw an
unimplemented error.
Process memory usage#
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:
import type { Flags, MemoryUsage, Resolve, Runtime } from "@rcompat/runtime";runtime.name#
runtime.name: string;A string identifying the current runtime environment.
runtime.bin#
runtime.bin: string;Full path to the runtime executable. This is an empty string in browsers.
runtime.script#
runtime.script: string;Full path to the currently executing script. This is an empty string in browsers.
runtime.args#
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#
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()#
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#
runtime.resolve(specifier: string, from: string): stringResolve a path or package specifier from a directory.
- Relative specifiers like
./foo.jsonand../tsconfig.jsonare resolved fromfrom - Absolute paths are returned as absolute paths
- Package specifiers like
apekit/tsconfigare resolved using the current runtime’s package resolution
Filesystem and package helpers#
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.
{
"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:
// 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#
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#
import runtime from "@rcompat/runtime";
const logger = {
info(message) {
console.log(`[${runtime.name}]`, message);
}
};
logger.info("Server started");
// [node] Server started
// [bun] Server startedEnvironment checks#
import runtime from "@rcompat/runtime";
const isServerRuntime = ["node", "bun", "deno"].includes(runtime.name);
const isClientRuntime = runtime.name === "browser";Debug information#
import runtime from "@rcompat/runtime";
function getDebugInfo() {
return {
runtime: runtime.name,
script: runtime.script,
args: runtime.args,
timestamp: Date.now(),
};
}Reading active conditions#
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.