\

Show HN: Nub – A Bun-like all-in-one toolkit for Node.js

128 points - today at 2:14 PM

Source
  • colinmcd

    today at 2:23 PM

    Colin here, creator of Nub. I’ve had the general shape of this in mind for years. Nub runs your code with stock `node`, augmented with a `--require` preload hook[0] that adds a transpiler (oxc-powered, packaged as a Node-API add-on), registers a module resolution hook[1], and injects polyfills as needed for APIs like `Worker`, `Temporal`, etc. All purely additive, your code ultimately runs using Node’s actual engine & stdlib implementations.

    [0] https://nodejs.org/api/cli.html#-require-module

    [1] https://nodejs.org/api/module.html#moduleregisterhooksoption...

      • eyelidlessness

        today at 4:44 PM

        I’m surprised to see this using a `--require` hook (rather than `--import`). Maybe something’s changed significantly since I was looking into building some similar functionality… but it makes me wonder about nuances in nub’s ESM support.

        (When I was investigating this it was very early in Node’s `--import` story, but there were several edge cases with the more common ESM-to-CJS approaches that I wanted to address. Most were probably exceedingly niche concerns, but I’d expect top-level await to affect a meaningful subset of users.)

          • colinmcd

            today at 5:39 PM

            We use this to register our preload purely for performance reasons. In this and many other cases CommonJS is still faster than ESM. Using --require is about 0.5ms overhead vs 4.6ms for --import (on my M1 Macbook Pro).

            Relatedly Node.js recently (2025) introduced a synchronous version of its resolver hook registration API (`module.registerHooks()`) specifically to improve performance over the old async `module.register()` API. It was a big unblocker for Nub. For the interested, the async API added 19ms fixed registration overhead + about 130us additional overhead per import.

            Which flag Nub uses here doesn't impact userland at all, TLA is supported wherever it's supported by Node.js itself.

        • awaseem

          today at 3:59 PM

          I saw this on twitter and loved it, such a good move on your part Colin. Hope the project picks up tons of steam!

      • ivanjermakov

        today at 4:09 PM

        Respect for embracing existing tech instead of rewriting a worse version of it. Wonder where we would be today if all alternative-building effort went to Node instead (with proper leadership).

          • johnfn

            today at 5:01 PM

            You might remember the io.js fork of Node.js back in 2014. Node was stagnating, a bunch of people forked it into io.js, which eventually got merged back into Node and got it back on track. Or, going further back, CoffeeScript, a "fork" of JS that had its best ideas adopted back into ES5.

            A small scrappy team can prove out a good idea because failure is not a catastrophic risk to them. In short, forks are part of a healthy ecosystem.

              • hootz

                today at 5:48 PM

                It is still happening, a lot of things are still being adopted by Node after being available on other runtimes. They aren't forks, but they still provide pressure towards progress.

            • hungryhobbit

              today at 4:44 PM

              Fundamentally you can't fix a lot of things with this approach.

              Simple example: Node is the only serious OSS software I know of that has no way to document its config (in the config file itself). It's moronic! The Node people just adopted JSON without a thought, and then refused to consider any alternatives (even "JSON with comments").

              When an organization digs into bad decisions, the only way to fix them is to start something new. The entire JS ecosystem will never have documentation on its config as long as everyone keeps building on top of Node.

              (And there are many other issues like this in the Node ecosystem; the utter absurdity of not being able to document config is just my personal pet peeve.)

                • johnfn

                  today at 5:02 PM

                  > Simple example: Node is the only serious OSS software I know of that has no way to document its config (in the config file itself). It's moronic! The Node people just adopted JSON without a thought, and then refused to consider any alternatives (even "JSON with comments").

                  Tangential but this also drives me absolutely nuts. If I have to see `"//": "some comment"` one more time I'm gonna lose it.

          • gorjusborg

            today at 3:38 PM

            Very smart. You can't lose all your customers for vibe-coding a migration to Rust if you are already written in Rust ;)

              • Zambyte

                today at 3:59 PM

                They'll get bought out by OpenAI and convert the project to Zig

                  • airstrike

                    today at 5:07 PM

                    huh, is OpenAI embracing Zig specifically? TIL

                      • allthetime

                        today at 5:49 PM

                        It’s a joke about how Anthropic bought bun and then rewrote bun from zig to rust with a giant one week vibe code. The joke hinges on the fact that this would be the opposite (OpenAI, nub, rust to zig)

                          • airstrike

                            today at 5:55 PM

                            oh LOL I'm slow today ig

                • lacoolj

                  today at 4:59 PM

                  It also helps if you're already vibe-coded and don't have customers to begin with

                  • skrebbel

                    today at 5:12 PM

                    Bun had customers?

                • ssalbdivad

                  today at 2:57 PM

                  Just merged a PR migrating our entire monorepo to nub.

                  0 issues, ridiculously fast.

                    • daavin

                      today at 3:18 PM

                      You merged a PR migrating a shared monorepo using this within an hour of it being posted?

                        • colinmcd

                          today at 4:39 PM

                          It entered public beta last week, but just getting on HN now.

                  • skybrian

                    today at 4:45 PM

                    > TypeScript-friendly resolution: extensionless imports, tsconfig.json#paths

                    I’m wondering how that works. Deno has very complicated import resolution, so building my own import resolver to be compatible with it is a bit of a pain. (This is for a custom lint-like tool.)

                    • kandros

                      today at 4:14 PM

                      Love the idea, learning a lot of interesting things about node hooks by reading docs and some code

                      • sgarrity

                        today at 3:21 PM

                        I didn't even click on the link. I just came to give the author a hat-tip on the project name. Well played.

                          • colinmcd

                            today at 3:26 PM

                            Thanks :) Highly recommend clicking the link too!

                        • bookernath

                          today at 3:08 PM

                          Nice, I think this fills a niche. Does it work on cloudflare workers?

                            • colinmcd

                              today at 3:17 PM

                              Cloudflare Workers is a different runtime and has its own toolchain around it. Nub could theoretically support it when executing files (spawn `wrangler dev` instead of `node` if wrangler.toml is detected or something) but really I'm focused on making the Node.js experience as good as possible.

                              The other pieces of the toolkit could absolutely be used: package manager, script runner, package runner. Works with anything that implements the Node module resolution algorithm (actually Yarn PnP also works out of the box...).

                          • montroser

                            today at 4:34 PM

                            Nice. Can we get `nub --compile` up in there like Bun has?

                              • colinmcd

                                today at 4:38 PM

                                Coming very soon!

                                  • allthetime

                                    today at 5:51 PM

                                    I will seriously consider migrating once this exists! I couldn’t imagine deploying any other way now. I can never go back from SCPing a single binary to my server and just hitting reset on the service.

                            • GL26

                              today at 3:13 PM

                              nice ! does this work on docker containers ?

                                • colinmcd

                                  today at 3:25 PM

                                  Yep, full support on macOS, Linux, Windows. No official image yet (I'll start on this now) but you can get started with something like this.

                                    FROM node:26-slim
                                    RUN npm i -g @nubjs/nub
                                  
                                  Works with any Node version down to 18.19 but recommend 22.15+ for best performance (that's when synchronous registerHooks was introduced[0])

                                  [0] https://nodejs.org/api/module.html#moduleregisterhooksoption...