Skip to content
Ayhan Sipahi Ayhan Sipahi

Nub vs Vite+: Two Rust Toolchains for Opposite Ends of the JS Stack

Nub and Vite+ are both 2026 oxc-powered Rust toolchains that look like rivals but are not. A senior engineer's rule for which binary belongs in which repo.

The JavaScript toolchain is still a stack of separate parts: a package manager, a runtime, a TypeScript runner, a bundler, a test runner, a linter, and a formatter, each with its own config file and its own version drift. Two 2026 projects promise to collapse that pile into one fast Rust binary: Nub and Vite+. Both are oxc-powered, single-binary, and shipped weeks apart, so engineers keep filing them as rivals. They are not. Vite+ owns the browser-facing application pipeline; Nub owns the stock-Node process. The rule is that simple: if your build output loads in a browser, standardize on Vite+; if it runs as a Node process, reach for Nub. The numbers below are vendor micro-benchmarks on specific scenarios, not independent measurements.

What Vite+ owns

Vite+ is a single vp command that unifies the web-development workflow. It reached beta on July 2, 2026 (the alpha was March 13, 2026). The command surface covers the whole browser-facing pipeline:

vp dev        # HMR dev server on Vite 8
vp check      # Oxlint + Oxfmt + type check in one pass
vp test       # Vitest
vp build      # production build (Rolldown)
vp pack       # bundle a library (tsdown)
vp run build  # monorepo-aware task runner with caching

Under the hood it bundles Vite, Vitest, Rolldown, tsdown, Oxlint, and Oxfmt behind that one binary, and it also manages the runtime and the package manager. It is fully open source under MIT, and vp create and vp migrate handle scaffolding and moving an existing Vite project across.

The trade-off is coupling. You stop configuring six tools directly and start trusting one integrated stack. When an edge case shows up in a plugin or a framework, you debug through the abstraction instead of the tool. In practice vp migrate does most of a plain-Vite migration, but the guide is explicit that complex projects still need manual follow-up. The upside is depth: Vite 8, Rolldown, and Vitest are the ecosystem defaults, so the parts inside the binary are the parts most teams already ship.

What Nub owns

Nub is a Bun-like developer experience on top of stock node, written in Rust. The design stance is the opposite of a new runtime: it augments Node instead of replacing it. It ships as @nubjs/nub, launched in June 2026, and reached v0.4.x within weeks. The author is Colin McDonnell, the creator of Zod and formerly of Bun.

nub server.ts        # run TypeScript on the Node the project pins
nub watch server.ts  # same, on Node's built-in --watch
nub install          # pnpm-compatible install, existing lockfiles work
nubx tsc --noEmit    # run a bin without a global install
nub node 22          # version manager, replaces nvm/fnm/n/volta

The headline command is nub <file>. It transpiles TypeScript in memory via oxc, loads .env, resolves tsconfig path aliases, and then runs the result on the stock Node the project pins. That single command replaces node, tsx, ts-node, and dotenv-cli. Around it sit a script runner (nub run), a bin runner (nubx / nub dlx), a pnpm-compatible package manager (nub install), a watch mode built on Node’s own --watch, and a version manager (nub node) that stands in for nvm, fnm, n, and volta. The stated design goal is no new runtime, no vendor-specific API surface, and no lock-in; it stays compatible with existing npm, pnpm, and yarn lockfiles.

The trade-off is maturity, not lock-in. Nub is at v0.4.x and is effectively single-maintainer, though a credible one. Because it augments rather than replaces, the exit cost is close to zero: your lockfiles keep working, and removing it drops you back on node, tsx, and pnpm with no migration. The risk lives in early-stage bugs on the transpile-and-run path and in gaps against mature version managers, not in a runtime you cannot leave.

A fair objection here is why not just use Bun. Nub is Bun’s developer experience without Bun’s runtime bet: the same one-binary ergonomics, the opposite decision about what runs your code. Bun replaces the runtime. It runs on JavaScriptCore with its own transpiler and bundler, and its 2026 Rust rewrite, now under Anthropic, makes it another single fast Rust binary, but not an oxc one and not stock Node. Nub keeps the Node your production already runs and only augments it: oxc transpiles in memory, then the exact stock V8 you pin executes the result. That one difference is the whole reason to stay on stock Node. A service that must match a Node deployment’s runtime semantics, a native addon compiled against Node’s ABI, or a team that will not re-qualify a runtime just to gain a faster install all point back to Nub. If none of those bind you, the override stands: switch to Bun or Deno, and Nub solves a problem you no longer have.

The single slot where they overlap

Read the two command surfaces side by side and the confusion dissolves. They point in opposite directions almost everywhere.

CapabilityVite+Nub
Browser dev server (HMR)Yes (vp dev)No
Production browser bundleYes (vp build)No
Library bundlingYes (vp pack)No
Test runnerYes (vp test)No
Lint and formatYes (vp check)No
Monorepo task runnerYes (vp run)Partial (nub run dispatch)
Run backend TS on stock NodeNoYes (nub <file>)
Package managerYesYes (nub install)
Runtime and version managementYesYes (nub node)

The only rows where both say yes are the last two: package manager and runtime or version management. That is the plumbing. Everything above it points up toward the browser artifact for Vite+ and down toward the Node process for Nub. So the only genuine collision is who owns the plumbing slot in a repo that has both a frontend and a backend. In a full-stack monorepo, let the more mature, ecosystem-backed option own the shared plumbing. Today that is Vite+, because it sits on Vite 8 and the broad Vite ecosystem and is now backed by Cloudflare. Nub then earns its place specifically for running and watching the backend and CLI TypeScript on stock Node.

Deciding from the artifact

Root the decision at the artifact you ship, not at the feature list. The feature lists overlap enough to mislead; the artifacts never do.

Yes, a web app or meta-framework app

No, a Node service, CLI, or library

Yes, production parity or native addons

No, a different runtime is fine

Yes

No

Yes

No

Yes

What are you shipping?

Loads in a browser?

Vite+ owns the toolchain

Must stay on stock Node?

Nub for run, watch, install

Consider Bun or Deno, not Nub

Full-stack monorepo with both?

Vite+ owns PM and runtime, Nub runs the backend TS

Pre-1.0 risk acceptable?

Stay on plain Vite 8 and assemble tools

Pre-1.0 risk acceptable?

Stay on tsx, pnpm, fnm

The default reads cleanly in two lines. When the output loads in a browser, Vite+ owns the toolchain. When the output is a Node process that must stay on stock Node, Nub owns run, watch, and install. The branches only exist to name the overrides: a willingness to switch runtime points to Bun or Deno instead of Nub, and an unacceptable pre-1.0 risk points back to the boring assembled stack on either side.

Reading the vendor numbers honestly

Every number here is vendor-published on a specific micro-scenario. I have not reproduced any of them. Attribute the source and name the scenario before you repeat a ratio.

  • Production build. VoidZero reports Vite+ builds are roughly 1.6x to 7.7x faster than Vite 7, and cites Linear’s build dropping from 46 seconds to 6 seconds. The range is wide because the speedup depends on the project.
  • Lint and format. Oxlint is cited at up to about 100x faster than ESLint, with 600+ ESLint-compatible rules, and Oxfmt at up to about 30x faster than Prettier, with roughly 99% Prettier compatibility.
  • Script dispatch. Nub reports its run dispatch (a warm no-op echo) at about 24x versus pnpm run, but only about 2.2x versus Node’s own node --run. Nub is explicit that the absolute numbers are machine-specific and only the ratios travel.
  • Bin runner. nubx is cited at about 19x to 20x versus npx.
  • Install. Nub’s README claims 18x faster pnpm install, while secondary write-ups report closer to 2.5x. Same tool, different cache state (warm no-op versus cold). Name the scenario or drop the number.

The install figure is the clearest warning. A headline “24x faster than pnpm run” quietly becomes about 2.2x once you compare against node --run on Node 22 and later. The ratio you quote is only as honest as the baseline you picked, so pick the baseline your team actually runs today.

One binary for everything

Collapsing seven tools into one binary re-introduces the coupling the JavaScript ecosystem spent a decade escaping. Whether that is progress or a new monolith comes down to one question: how expensive is it to leave?

Vite+ leans fully into integration. It owns the dev server, the bundler, the test runner, the linter, the formatter, the task runner, and the package-manager and runtime slots. Its strategic backing also changed: VoidZero announced it is joining Cloudflare on June 4, 2026. At the same time it grew more open, not less. The original October 2025 plan was commercial and source-available, free only for individuals, open source, and small businesses; that reversed at the March 2026 alpha, and the beta remains fully MIT. So the license risk fell while the surface area it owns grew.

Nub makes the opposite bet. It augments stock Node instead of replacing it, ships no vendor-specific API, and keeps working with your existing lockfiles. You can remove it and land back on node, tsx, and pnpm with no migration.

That is the honest way to read the monolith question. Consolidation is progress where the binary absorbs configuration you never wanted to own, such as the six lint, format, and bundler configs that only ever fought each other. It becomes a monolith risk where it absorbs decisions you want to keep reversible, such as which runtime runs your production service or who owns your package graph. Judge each binary by its exit cost, not by its install-speed chart.

When to reach for something else

Three cases fall outside the default.

  • A pure static site with a trivial toolchain. Neither binary earns its place; a plain bundler or a framework’s built-in tooling is enough.
  • You already run Bun or Deno in production. Nub’s whole premise is stock-Node parity, so it solves a problem you do not have; your runtime already collapsed the toolchain.
  • You need a mature monorepo task graph today. vp run is newer and simpler than Turborepo or Nx. If you depend on a proven task graph with remote caching at scale, keep the tool you trust and let Vite+ own only the parts it clearly leads.

Under all three sits the pre-1.0 question. Vite+ is in beta and Nub is pre-1.0 (v0.4.x). If pre-1.0 risk is unacceptable for the repo in question, the fallback is boring and fine: plain Vite 8 with assembled tools on the frontend, and tsx plus pnpm plus fnm on the backend.

Common pitfalls

  • Treating them as head-to-head competitors and letting an install-speed number pick the winner. They sit on different layers.
  • Adopting Nub and expecting a browser dev server or a production browser bundle. It has neither.
  • Adopting Vite+ to run a backend service you never bundle for a browser. That is not what vp is for.
  • Repeating a vendor benchmark as a measured fact. Each number is tied to one micro-scenario, so attribute it.
  • Quoting Nub’s 24x run figure without noticing it is about 2.2x against node --run. The headline depends entirely on your current baseline.

Conclusion

The rule holds for the common cases. If the build output loads in a browser, or you need one tool to own a full-stack monorepo’s package-manager and runtime slot, standardize on Vite+. If the build output is a Node process (a backend service, a CLI, a library, or a pile of scripts) and it must stay on stock Node, reach for Nub to run, watch, and install. They are not substitutes, so let the artifact decide, and do not draft either one to do the other’s job. Reach for an override when the toolchain is trivial, when you already run Bun or Deno, or when pre-1.0 risk is off the table for that repo.

This comparison maps the tools; it does not benchmark them. The next step is a small, conceptual POC: run one TypeScript service under nub and one web app under vp, and record where each abstraction leaks. Until that runs, treat every ratio above as a vendor claim tied to a specific scenario, not a measured result.

References

Related posts