Back to Scaling Node.js applications guides

Nub: An All-in-One JavaScript Toolkit That Augments Node.js

Stanley Ulili
Updated on August 3, 2026

The Node.js development experience typically involves a small collection of separate tools: tsx or ts-node for running TypeScript, nvm for Node version management, dotenv for environment variable loading, npx for package binaries, and npm run or pnpm run for scripts. Each works fine independently, but together they add configuration overhead and startup latency.

Nub, launched on June 15, 2026 by Colin McDonnell (creator of Zod, former Bun employee), replaces all of them with a single Rust binary. Its distinguishing design choice is to augment Node.js rather than replace it. You keep the stock Node runtime your project already pins; Nub adds TypeScript support, faster script dispatch, package management, Node version management, and .env loading on top of it. On Deno's own Node compatibility corpus, Nub passes 98.8% of what real Node passes, versus 77.4% for Deno and 40.5% for Bun.

The project is at v0.4.x, MIT-licensed, and available at github.com/nubjs/nub.

Installation

Nub runs on macOS, Windows, and Linux.

Install via the shell script:

 
curl -fsSL https://nubjs.com/install.sh | bash

Or via npm:

 
npm install -g @nubjs/nub

Or via Homebrew on macOS:

 
brew install nubjs/tap/nub

A screenshot of the Nub.js homepage showing the primary installation command.

Verify the installation:

 
nub --version

Running TypeScript files

Node.js added TypeScript type-stripping in recent versions, but it only handles types that can be erased. Code that uses enum, namespace, or constructor parameter properties fails with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX because these features have no direct JavaScript equivalent.

Nub uses oxc for transpilation and handles all TypeScript syntax correctly:

strip-limits.ts
enum Status {
  Draft,
  Published,
  Archived,
}

namespace Meta {
  export const engine = "oxc";
}

class Money {
  constructor(
    public currency: string,
    private amount: number,
  ) {}
}

console.log('enum:', Status.Published);
console.log('namespace:', Meta.engine);
const myMoney = new Money('GBP', 38.24);
console.log('param properties:', myMoney);
 
nub demos/type-stripping/strip-limits.ts

The terminal output after running the TypeScript file with Nub, showing the successful execution and printed logs, contrasted with a note indicating where standard Node.js would fail.

Automatic .env loading

Nub detects and loads environment variable files without any configuration or dotenv dependency. It checks for files in this order of precedence:

  1. .env
  2. .env.local
  3. .env.[NODE_ENV]
  4. .env.[NODE_ENV].local

Variable expansion is handled automatically. You can compose variables from other variables in the same file:

.env
DB_HOST=localhost
DB_PORT=5432
DB_USER=admin

DATABASE_URL=postgres://${DB_USER}@${DB_HOST}:${DB_PORT}/kitchen_sink

DATABASE_URL is resolved and available in process.env when you run any file with Nub.

An example `.env` file within a code editor, highlighting the line with `DATABASE_URL` to showcase the variable expansion syntax.

Data file imports and path aliases

Data file imports

Nub lets you import JSON, YAML, TOML, and plain text files directly as modules:

 
import config from './config.json';
import settings from './settings.yaml';
import serverConfig from './server.toml';
import motd from './motd.txt';

Path aliases

If your tsconfig.json defines path aliases, Nub resolves them automatically at runtime without needing tsconfig-paths or any additional setup:

tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@config/*": ["./config/*"],
      "@/lib/*": ["./src/lib/*"]
    }
  }
}

A screenshot of a `tsconfig.json` file, with the "paths" object highlighted to show how aliases are configured.

 
import serverConfig from '@config/server.toml';
import { render } from '@/lib/ui';

Modern APIs and polyfills

Nub polyfills modern web APIs on older Node versions and auto-enables experimental Node features so you don't need to pass command-line flags manually.

![A grid view from the Nub website listing the various modern APIs and syntax that a

frame_2_43.jpg

Included polyfills:

  • Web Workers: browser-shaped Worker constructor over node:worker_threads
  • Temporal API: native in Node 26+; polyfilled with @js-temporal/polyfill on older versions
  • URLPattern: native in Node 24+; polyfilled on older lines
  • using / await using: explicit resource management
  • Decorators: class and method meta-programming

Node version management

Nub includes an automatic Node version manager. When you run any nub command in a project, it checks for a version specification in this order:

  1. .node-version file
  2. .nvmrc file
  3. engines field in package.json

If the specified version isn't installed, Nub downloads it on demand:

Output
Installing from nodejs.org... (28 MB)
Installed in 2.4s
Using Node.js 24.18.0

For manual version management:

 
nub node install 23
 
nub node ls
 
nub node uninstall 23.11.1
 
nub node pin 26

nub node pin creates a .node-version file in the project directory, which Nub (and other compatible tools) will pick up automatically.

Package management

Nub's package manager is built on the Aube engine. The key design decision is lockfile compatibility: rather than introducing a new lockfile format, Nub reads and updates whichever lockfile your project already uses.

  • package-lock.json (npm)
  • pnpm-lock.yaml (pnpm)
  • bun.lock (Bun)
 
nub install

nubx instead of npx

nubx replaces npx for running package binaries. Where npx is a Node.js script that boots a process and resolves the binary through JavaScript, nubx is a native Rust binary that resolves the path in node_modules/.bin directly and executes immediately.

 
nubx prettier --write .

nub run for scripts

nub run replaces npm run and pnpm run for executing package.json scripts. It reads package.json natively in Rust and spawns the process directly, avoiding the JavaScript startup penalty. Lifecycle hooks, argument forwarding, and npm_* environment variables all work as expected.

 
nub run dev

The performance numbers Nub publishes are vendor benchmarks on specific scenarios, not independent measurements, so treat them as directional rather than absolute. The architectural reason for the improvement is real: eliminating a Node.js process just to dispatch another Node.js process removes meaningful overhead, especially in CI and monorepos where scripts run frequently.

Design philosophy

Nub introduces no Nub-specific APIs. There is no nub global, no nub: prefixed built-in modules, no Nub-named config file, no Nub lockfile, and no NUB_ environment variables. It uses Node's own public extension surfaces: module.registerHooks(), --import preloads, and N-API native addons. If you stop using Nub, your code still runs with stock Node.

One caveat worth noting: Nub transpiles TypeScript but does not type-check it. You still need tsc --noEmit in CI for type safety. Nub is a development and script execution toolkit, not a production runtime.

The official introduction post at nubjs.com/blog/introducing-nub covers each feature in more depth, including the polyfill implementation details and the compatibility methodology.

Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.