Apresentando o Nub, um Toolkit All-in-One para Node.js
Nub é um toolkit Rust para Node.js que executa TypeScript, scripts, instalações e versões do Node no Node padrão, preservando lockfiles e segurança.
O Nub é um toolkit de linha de comando escrito em Rust para Node.js. Ele transpila TypeScript, despacha scripts do package.json, instala dependências e provisiona versões do Node, e então entrega a execução ao binário node padrão que o seu projeto já fixa. Ele complementa o Node em vez de substituí-lo, e é justamente aí que reside toda a diferença entre ele e o Bun ou o Deno.
A maioria das equipes que avaliou Bun e Deno frente ao Node nunca passou da primeira pergunta: você não troca o runtime por baixo de um serviço em produção só porque a experiência de desenvolvimento é mais agradável. O Nub segue o caminho oposto, apresentando-se como um toolkit em Rust que deixa o seu Node, o seu lockfile e o seu gerenciador de pacotes exatamente onde estão. Eis o que isso lhe oferece e quanto custa experimentar.
Principais Conclusões
- O Nub é uma CLI em Rust que adiciona execução de TypeScript, despacho de scripts, instalação de pacotes e gerenciamento de versões do Node sobre o binário
nodepadrão, de modo que não há um novo runtime a ser homologado. - O suporte nativo a TypeScript do Node apenas remove anotações e rejeita qualquer coisa que exija código gerado, como enums, parameter properties ou um namespace contendo código de runtime; o loader do Nub compila essas construções.
- O instalador do Nub tem formato pnpm-like e lê e grava lockfiles existentes de npm, pnpm e bun no próprio local, com lockfiles do yarn em modo somente leitura.
- As defesas de instalação não exigem configuração: scripts de build de dependências permanecem bloqueados até que você os aprove, cada nova resolução é verificada contra o OSV, e um limite de 24 horas de idade de release mantém versões recém-publicadas de fora.
- Não há APIs específicas do Nub nem lockfile do Nub, e o
nub.jsoncé opcional, portanto remover o Nub devolve o projeto ao Node puro.
O Que é o Nub e o Que Ele Não É?
O Nub não é um quarto runtime. É um único binário que se posiciona à frente do Node, faz o trabalho que hoje exige tsx, nvm, npx e um gerenciador de pacotes, e então executa o Node de verdade. Sua página inicial descreve o mecanismo sem rodeios: o oxc compila seus arquivos em memória de dentro de um addon nativo, e o binário node padrão executa o resultado. Não há runtime separado por baixo, e o executor de arquivos aceita as mesmas flags que o node.
Nada no seu alvo de deploy muda. A versão do V8, a ABI de C++ contra a qual seus módulos nativos foram compilados, a superfície de process na qual sua instrumentação se conecta, tudo isso continua sendo o mesmo Node que você já estava entregando. O caminho aumentado requer Node 18.19 ou superior (Node 18 LTS), em macOS, Linux e Windows, cada um em x64 e arm64.
O projeto é recente. O pacote npm @nubjs/nub é publicado sob licença MIT e ainda está pré-1.0, na linha 0.9.x na data do último release, com novas versões surgindo com frequência.
Como o Nub Executa TypeScript Sem Etapa de Build?
O suporte nativo a TypeScript do Node remove tipos em vez de compilá-los. As anotações são substituídas por espaços em branco, e qualquer coisa que exigiria a geração de JavaScript é rejeitada. A documentação do Node lista os casos: enums, namespaces que contêm código de runtime, parameter properties e aliases import = todos levantam ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX; decorators falham no parsing; e como o Node nunca abre o tsconfig.json, aliases de paths não são aplicados. Um modo de transformação mais completo ficava atrás de --experimental-transform-types, mas o Node removeu essa flag na versão 26, de modo que a erasure é agora o único caminho embutido.
Essas exclusões são exatamente a sintaxe da qual uma base de código NestJS ou TypeORM é feita. Considere um arquivo que usa um enum, uma parameter property e um import relativo sem extensão:
// invoice.ts
import { Model } from "./base"
enum Status { Draft, Sent, Paid }
export class Invoice extends Model {
constructor(public status: Status = Status.Draft) {
super()
}
}
Com node invoice.ts puro, o enum e a parameter property não são removíveis e o import não tem extensão. Com nub invoice.ts, o mesmo arquivo roda sem alterações. O Nub entrega cada arquivo ao seu addon nativo para compilação, e é por isso que o enum, a parameter property e o import sem extensão funcionam. Ele também percorre o seu tsconfig.json e qualquer configuração que esse arquivo extends, e então repassa os aliases de paths ao próprio resolver do Node por meio de um resolve hook de module.registerHooks().
Decorators são suportados em apenas um formato. O post de lançamento cobre os legacy experimentalDecorators, a forma para a qual NestJS, TypeORM e Angular foram escritos, junto com emitDecoratorMetadata. Decorators Stage 3, que o TypeScript 5 usa por padrão, são rejeitados, porque a transformação ainda é uma lacuna em aberto no oxc. O executor emite source maps inline, de modo que os stack traces apontam para o seu código-fonte em vez de para a saída gerada. Esse último detalhe não é cosmético: TypeScript transpilado que perde seus source maps produz traces contra um código que ninguém escreveu, uma fonte recorrente de tempo desperdiçado em triagem.
Quais Comandos o Nub Substitui?
O binário único do Nub cobre trabalho hoje dividido entre uma prateleira de ferramentas. O mapeamento de substituição documentado é direto:
| Comando Nub | Substitui |
|---|---|
nub <file> | node, tsx, ts-node, dotenv-cli |
nub run <script> | npm run, pnpm run, yarn run |
nubx | npx, pnpm dlx, pnpm exec, yarn dlx |
nub install | npm, pnpm, yarn |
nub watch | nodemon, node --watch, tsx watch |
nub node | nvm, fnm, n, volta |
nub pm | corepack |
Essa tabela não cobre toda a superfície. O README também descreve o nubr, um único comando que executa um arquivo, um script do package.json ou um bin de node_modules/.bin, tentando nessa ordem. Ele é distribuído separadamente como @nubjs/runner para projetos que não podem instalar um binário.
A propriedade importante é que esses recursos são independentes. Adotar o executor de arquivos não obriga você a adotar o instalador, e trocar um script dev de tsx watch src/server.ts para nub watch src/server.ts mantém o package.json como um manifesto normal, compatível com npm. O projeto divulga seus próprios benchmarks para as alegações de velocidade: 24× mais rápido que pnpm run no despacho de scripts, 19× mais rápido que npx na execução de bins e 18× mais rápido que pnpm install. Os tempos pareados do README colocam o despacho de scripts em 14,7 ms contra 329,9 ms do npm, e uma instalação frozen “quente” em 171 ms contra 3193 ms do pnpm, ambos medidos em macOS. Um segundo benchmark de instalação, executado com hyperfine em um runner ubuntu-latest sobre uma árvore de 1.168 pacotes, reporta 346 ms para o Nub e 3453 ms para o pnpm.
O Gerenciador de Pacotes: Formato pnpm-like e Preservação de Lockfiles
O instalador do Nub não introduz um formato de lockfile. Ele identifica qual gerenciador de pacotes o projeto já usa, a partir de package.json#packageManager ou de qualquer lockfile que encontre, e então roda em compat-mode, respeitando os arquivos de configuração e as variáveis de ambiente daquela ferramenta. A própria CLI tem formato pnpm-like, de modo que nub install, nub add -E -D react, nub remove, nub update e nub ci se comportam como a memória muscular espera.
Especificamente sobre lockfiles: lockfiles de npm, pnpm e bun são lidos e gravados no próprio local, e lockfiles do yarn são somente leitura. Nada é convertido, e nenhum segundo lockfile aparece no diff. Para uma equipe que usa pnpm, essa é a questão que decide se a ferramenta é sequer avaliável.
Resolução de Versões do Node Sem nvm
O nub node resolve a versão do Node que um projeto espera e a provisiona sob demanda. A versão vem de .node-version, .nvmrc ou package.json#engines, e uma versão ausente é baixada e colocada em cache automaticamente, com verbos explícitos também disponíveis: nub node install 26, nub node ls, nub node pin 26 e nub node uninstall 22. Ele faz isso sem shell hooks e sem reescrever seu PATH, que é justamente a parte do nvm que costuma quebrar em CI e em shells não interativos.
Padrões de Supply-Chain e a Ausência de Lock-In
As defesas do Nub em tempo de instalação vêm ativadas sem configuração. Quatro delas estão documentadas. Os scripts de build de uma dependência não rodam até que você aprove aquele pacote. Cada nova resolução é verificada contra o OSV em busca de versões reconhecidamente maliciosas. Uma versão que perdeu a evidência de confiança de publicação presente em um release anterior é recusada de imediato. E o minimumReleaseAge tem padrão de 24 horas, a mesma janela usada pelo pnpm, de modo que uma versão publicada há poucos minutos não pode chegar à sua árvore. O post de lançamento acrescenta que uma dependência transitiva que resolva para uma URL git+, file: ou de tarball bruto é recusada em vez de baixada silenciosamente. Se você já trabalhou em uma postura de defesa contra ataques de supply-chain no npm, isso é aquele checklist como padrão, e não como um .npmrc que você precisa manter.
A reversibilidade é a outra metade da promessa. O Nub não adiciona APIs para importar, não grava um lockfile próprio e trata o nub.jsonc como configuração opcional em vez de requisito. Desinstale o binário e o projeto roda em Node puro com o ferramental que tinha antes, porque o código-fonte nunca referenciou o Nub em primeiro lugar.
Quem Deve Experimentar o Nub e Quem Não Deve?
Experimente se você roda TypeScript via tsx ou ts-node, mantém o nvm por perto para fixar versões e preferiria não gastar um trimestre homologando um novo runtime para se livrar disso. Comece com o executor de arquivos em um único serviço, deixe o instalador de lado e veja se aquela classe de atrito de build envolvendo enums e decorators desaparece. Deixe para depois se você precisa de uma toolchain fixa e sem surpresas para um processo de release regulado, porque um projeto pré-1.0 lançando releases com dias de diferença ainda não é isso. O custo de descobrir é npm install -g @nubjs/nub e um comando sobre um arquivo que você já tem.
Perguntas Frequentes
Como executo um arquivo pelo Nub sem nenhuma augmentação?
Use o modo de compatibilidade: passe --node para uma única invocação, ou defina NODE_COMPAT como 1, true ou yes para cobrir toda a árvore de processos. Nesse modo o Nub não aplica absolutamente nada, portanto não há load hook, nem preload, nem injeção de flags, nem carregamento de .env. Ele ainda identifica qual Node o projeto fixa e o instala se necessário, de modo que seu código roda em modo vanilla na versão correta. Isso o torna útil para distinguir um bug do Nub de um bug do Node.
Quais plataformas e versões do Node o Nub suporta?
O Nub distribui binários Rust pré-compilados para Linux, macOS e Windows, em x64 e arm64, e baixa o addon N-API correspondente à sua plataforma no momento da instalação. Os modos aumentados exigem Node 18.19 ou superior, porque é nessa versão que a API de loader hooks por trás do caminho de transpilação-no-import aparece pela primeira vez. Em qualquer versão anterior, um comando aumentado é interrompido com um erro que informa o piso de versão e aponta para o modo de compatibilidade.
Por que uma instalação falha com ERR_NUB_ALLOW_BUILDS_RENAMED?
O Nub 0.9.0 renomeou a allowlist de builds de nível superior no package.json de allowBuilds para allowScripts, coincidindo com o campo que o npm 12 lê. Um projeto que ainda mantenha um mapa allowBuilds na raiz é recusado com esse erro em vez de apenas receber um aviso, então a correção é renomear a chave. O allowBuilds do pnpm é uma configuração diferente e não é afetado, esteja ele em pnpm-workspace.yaml ou sob package.json#pnpm.
Posso usar o nubx sem trocar de gerenciador de pacotes?
Sim. O nubx encontra uma CLI instalada localmente em node_modules/.bin, seja lá o que a tenha colocado ali, então funciona em um projeto instalado por npm, pnpm, yarn ou bun sem migrar nada. Ele aceita as flags do pnpm exec com os mesmos nomes, e o nub dlx espelha o pnpm dlx até no modo shell, de modo que as linhas de comando que você já tem continuam funcionando.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k