nub.jsonc — The config file for Node.js you always wanted
The node CLI doesn't try too hard to be ergonomic. It's designed like a util, with lots of explicit flags and environment variables. Even as new features like "node:test" and watch mode have landed, Node has studiously avoided adding any subcommands (e.g. node test or node watch), favoring --test and --watch instead. It's not uncommon to see large node commands like this in package.jsons or other scripts.
As a matter of fact, Node quietly shipped a config file in Node v22.16 last year (node.config.json). But it's disabled by default and (rather antithetically) gated behind a scary-looking flag.
node --experimental-default-config-file index.ts
This is the kind of ergonomic issue in Node.js that Nub is perfectly equipped to solve.
Nub is an all-in-one Rust toolkit for Node.js. The nub CLI is flag-for-flag compatible with node, while adding a TypeScript-first runtime, script and package runners, a pnpm-compatible package manager, and Node version management—all on stock Node.
nub index.ts # supports TypeScript, JSX, Worker, latest ECMAScript syntaxnub run dev # run package.json scriptsnub install # install using your existing lockfilenubx prisma generate # run package CLIsnub node install 26 # pin and provision Node
In v0.7, Nub introduced its config file nub.jsonc. It's the config file for Node.js you've always wanted, with the current runtime fields in one place:
As of Nub v0.7, Nub has first-party Varlock support. If a project has a .env.schema and Varlock is installed, Nub hands environment loading to Varlock automatically.
Preloads can also establish process-wide behavior that application modules should not have to initialize themselves. This formatter removes dependency frames from V8 stack traces before the entry point runs, including in scripts, tests, and CI:
Node accepts V8 flags on its command line but excludes many of them from NODE_OPTIONS. v8Flags keeps those options in project configuration while still passing them to the project-selected Node, which validates them at startup. Options that Node already permits in NODE_OPTIONS, such as --max-old-space-size, belong in nodeOptions instead:
I've written on my personal blog about ergonomic ways to maintain "live types" in a TypeScript monorepo. The approach I recommend registers one unique export condition in the package, TypeScript, and each runtime tool. With the same condition in tsconfig.json and nub.jsonc, TypeScript and Nub both resolve workspace imports directly to source while other consumers get the built package:
Under this configuration, your in-editor code will always get type information directly from your source files instead of showing possibly stale builds. Running your code with Nub will respect these same conditions.