← Back to Blog
June 25, 2026 7 min read

Nub: Bun-like DX without leaving Node

Bun tried to replace Node. Deno tried to replace Node. Both built new runtimes with new APIs, new package registries, new ways to do the same stuff. Some of it worked. A lot of it meant relearning things that already worked fine.

A project called Nub hit the Hacker News front page this week with a different pitch: keep Node, just make it faster. No new runtime. No vendor-specific APIs. No lock-in. A Rust binary that sits on top of stock Node and gives you the developer experience Bun promised, minus the compatibility headaches.

I spent a few hours reading their docs and running the benchmarks. Here is what I found.

What Nub actually is

Nub is a single Rust binary that augments Node.js from the outside. You do not switch runtimes. You do not rewrite your code. You swap node for nub, npm run for nub run, npx for nubx, and things get faster. That is the whole pitch.

It works by hooking into Node extension surfaces that mostly did not exist when Bun and Deno were built. --import and --require preloads. module.registerHooks() for transpilation and resolution. N-API native addons, where Nub embeds the oxc transpiler. These are official Node APIs. Nub uses them instead of forking the runtime.

The result is a toolkit that covers seven jobs most Node developers juggle across five separate tools:

One binary. Seven tools. That alone is appealing if you have ever tried to onboard someone and explained why they need four different package managers installed.

The benchmarks

Nub published benchmark harnesses you can run yourself. I like that. The numbers come from their repo, tested on macOS. Here are the ones that matter most day to day.

Script dispatch (warm, 50 runs)
pnpm run 442.7 ms
npm run 329.9 ms
nub run 14.7 ms
24-30x faster
Package runner (esbuild --version)
npx 226 ms
pnpm exec 191 ms
nubx 11 ms
17-19x faster
Frozen install (222 deps, create-t3-app)
npm 4163 ms
pnpm 2847 ms
bun 1444 ms
nub 1122 ms
29% faster than Bun
File runner startup (vs tsx)
tsx baseline
nub 2.9x faster
2.9x faster

Why the speed difference? The script and package runners are Rust binaries with no JavaScript startup of their own. When you run npm run build, npm boots a Node process just to read your package.json and dispatch the script. Nub skips that. It reads the manifest in native code and spawns Node only for your actual script.

The package manager numbers are impressive too. Nub beats Bun on frozen install by 29%, which is not something I expected. The engine underneath is Aube, a Rust-based package manager, and Nub wraps it with pnpm-compatible flag parsing.

The runtime trick

This is the part I found most interesting. Bun and Deno both fork V8 or JavaScriptCore and build their own module systems on top. Nub does not. It is a wrapper that launches your project's version of Node with specific flags injected.

When you run nub index.ts, Nub reads .node-version or package.json#engines, installs that version of Node if you do not have it, and then runs your file through stock Node with transpilation hooks registered via module.registerHooks() and oxc preloads via --import.

The effect is TypeScript and JSX running natively with zero config. Extensionless imports work. tsconfig.json paths resolve correctly. .env files load automatically. Experimental APIs like node:sqlite, WebSocket, and vm.Module work without flags. Polyfills for Temporal, URLPattern, and Float16Array kick in when your Node version is too old.

You are still running Node. The same V8. The same event loop. The same node_modules. You just get Bun-like features layered on top.

Security defaults that are not terrible

Package manager security is usually an afterthought. Nub makes it a default. Postinstall scripts are blocked unless you allow them. It checks osv.dev for known-malicious package versions during resolution. It refuses provenance downgrades. It enforces a 24-hour minimum release age by default.

These are all things you should configure in any package manager. Nub just turns them on without you having to remember. That is a small thing that matters a lot if you have ever been burned by a supply chain attack.

Compat mode is clever

You cannot rip out pnpm overnight. Nub knows this. When you run nub install inside a project that already has a lockfile, it detects which package manager owned that lockfile and runs in compatibility mode. It reads pnpm-lock.yaml if pnpm was the incumbent. It reads yarn.lock for Yarn projects. It reads bun.lock and bunfig.toml for Bun projects.

This means you can install Nub alongside your existing setup, try it on one project, and not blow up the rest. Incremental adoption. Not a rewrite.

What worries me

Nub is new. Very new. The GitHub repo shows active development but the team is small. The documentation is solid for the core features, but edge cases in any Node tool are bottomless. When something breaks in module.registerHooks() at 2am, you are debugging a Rust binary wrapping a C++ runtime, and the surface area for weird interactions is large.

I also wonder about the long-term pitch. "Same Node, faster" is a great selling point right now because Node's extension APIs are finally mature enough to make it work. But if Node itself ships better TypeScript support or faster script dispatch in a future version, Nub's advantage shrinks. The team is betting that Node moves slowly enough for Nub to stay ahead, which has been a safe bet historically but is not guaranteed.

The package manager compatibility is impressive on paper, but pnpm has years of edge-case handling that Nub has not run into yet. Large monorepos with custom .pnpmfile.cjs hooks or exotic workspace configurations might hit walls. I have not tested those scenarios.

When to try it

If you spend your day running npm run and npx in a TypeScript project, Nub is worth 15 minutes of your time. The speed difference is not theoretical. nub run build at 14ms versus pnpm run build at 442ms is a difference you feel every time you type it.

If you are evaluating Bun but nervous about the compatibility gaps, Nub is a lower-risk alternative. You keep Node. You keep your existing lockfile. You just add a faster dispatch layer on top.

If you are on a large team with a lot of pnpm infrastructure built up, wait. Nub's compat mode reads your lockfile fine, but your CI pipelines, your Dockerfiles, your onboarding docs all assume pnpm. Swapping the binary is easy. Swapping the org's muscle memory is hard.

If you maintain an open source project and want CI to be faster, the nubjs/setup-nub GitHub Action is a drop-in for actions/setup-node. That alone could shave seconds off every workflow run.

Installing

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

# Homebrew
brew install nubjs/tap/nub

# npm
npm install -g --ignore-scripts=false @nubjs/nub

Source code is at github.com/nubjs/nub. Docs are at nubjs.com/docs. The binary builds on macOS, Linux, and Windows.

Node.js Rust Tooling Open Source