hni

Fast package manager routing for npm, yarn, pnpm, bun, and deno.
hni is inspired by Antfu's ni, but packaged as a single multicall binary with extra shell setup for a node shim.
hni is still beta software and may have bugs.
One install gives you:
hnini,nr,nlx,nru,nun,nci,na,np,nsnodeshim viahni init <shell>(shell plugin only)
Install
npm (global)
This installs hni and the ni-family aliases (ni, nr, nlx, nru, nun, nci, na, np, ns) onto your global npm bin path.
The node shim is only enabled through hni init <shell>.
Under the hood, npm resolves a platform-specific optional dependency package that contains the native hni binary.
Homebrew
Script install (macOS / Linux)
TODO: https://happytoolin.com/hni/install.sh is not live yet. Use the raw GitHub script for now:
|
Optional environment variables:
HNI_VERSION- install a specific version, for examplev0.0.2HNI_INSTALL_DIR- install somewhere other than~/.local/binHNI_NODE=off- disable thenodeshim for the current environment
Script install (PowerShell)
TODO: https://happytoolin.com/hni/install.ps1 is not live yet. Use the raw GitHub script for now:
irm https://raw.githubusercontent.com/happytoolin/hni/main/install.ps1 | iex
Optional parameters:
-Version latest-InstallDir "$env:LOCALAPPDATA\hni\bin"
Deno / JSR
Install hni:
Install alias commands (example):
Commands
ni
Install dependencies or add new ones.
nr
Run package scripts.
nlx
Execute binaries without adding them permanently to your project.
nru
Upgrade dependencies.
Named nru to avoid shadowing Nushell's nu binary.
nun
Remove dependencies.
nci
Run a clean install. If a lockfile exists, hni uses the package-manager-specific frozen install command.
na
Print or forward directly to the detected package manager.
np / ns
Run shell commands in parallel or sequentially.
node
hni can also act as a package-manager-aware node shim.
Enable it by adding hni init <shell> to your shell config first.
Regular Node.js usage still passes through:
Utilities
Shell Setup
If you want node-shim behavior, add the init line at the end of your shell config file, after anything that manages Node or rewrites PATH, such as nvm, mise, asdf, fnm, or volta.
Do not append the hni directory to the end of PATH. Put the init line at the end of the shell config file and let it prepend the correct path for you.
zsh
Add to ~/.zshrc:
bash
Add to ~/.bashrc:
fish
Add to ~/.config/fish/config.fish:
hni init fish | source
PowerShell
Add to $PROFILE:
Invoke-Expression (& hni init powershell)
Nushell
Generate a stable init file, then source it from the end of ~/.config/nushell/config.nu:
hni init nushell | save --force ~/.config/nushell/hni.nu
source ~/.config/nushell/hni.nu
Global Flags
These work across hni and the multicall aliases:
Use -- to forward flags to the underlying package manager or script:
Configuration
Config file:
~/.hnirc
Supported keys:
defaultPackageManager=pnpm
globalPackageManager=npm
fastMode=true
Environment overrides:
HNI_CONFIG_FILEHNI_DEFAULT_PACKAGE_MANAGERHNI_GLOBAL_PACKAGE_MANAGERHNI_FAST
How It Works
hni detects the package manager from:
packageManagerinpackage.json- lockfiles such as
pnpm-lock.yaml,pnpm-workspace.yaml,yarn.lock,package-lock.json,bun.lockb, ordeno.lock devEngines.packageManagerinpackage.json- install metadata such as
.pnp.cjs,node_modules/.pnpm, ornode_modules/.package-lock.json - config defaults if detection is unavailable
Then it maps the command family to the right underlying command:
ni-> install or addnr-> run or tasknlx->npx/pnpm dlx/yarn dlx/bun xnru-> update / upgradenci-> frozen install when lockfiles exist
Troubleshooting
PowerShell ni alias conflict
PowerShell ships with a built-in ni alias for New-Item.
If that conflicts with hni, remove or override it in your profile before loading hni:
Remove-Item Alias:ni -ErrorAction SilentlyContinue
Invoke-Expression (& hni init powershell)
Check what hni resolved
Benchmarking
The active benchmark suite lives in benchmark/.
If you use just, the common local commands are wrapped in justfile:
Run the default local benchmark with:
Pass options through either entrypoint:
Run the full release-style matrix with:
Generate flamegraphs with:
Tracked benchmark docs:
- current snapshot:
benchmark/LATEST.md - lightweight history:
benchmark/HISTORY.md - fast-mode compatibility:
docs/fast-compat.md
Representative Results
The tracked snapshot in benchmark/LATEST.md was generated from the direct track with 2 warmups and 10 measured runs per case.
If you only want the headline, it is this: hni --fast averaged 5.44x faster than direct package-manager commands in the latest direct run.
The fast track compares pm mode versus fast mode inside hni across npm, pnpm, yarn, bun, deno, and local-bin execution. In the latest local fast run, hni --fast averaged 4.57x faster than pm mode.
A few representative wins:
| Case | pm | fast | Relative |
|---|---|---|---|
nr noop (npm) |
214.19 ms | 28.59 ms | 7.49x |
nr noop (pnpm) |
427.88 ms | 28.81 ms | 14.85x |
nr noop (yarn) |
264.11 ms | 28.85 ms | 9.16x |
node run noop (pnpm) |
429.05 ms | 29.00 ms | 14.80x |
node run noop (bun) |
33.82 ms | 29.00 ms | 1.17x |
nlx hello --flag (npm local bin) |
250.63 ms | 5.15 ms | 48.71x |
The direct track also compares normal package-manager usage (npm run, pnpm exec, yarn, bun x, deno task) with hni --fast. In the latest local direct run, hni averaged 5.44x faster, including local-bin wins for pnpm exec (52.40x) and yarn (16.98x).
Methodology
All timing uses hyperfine against the release binary. The suite can look at four angles:
direct: normal package-manager usage versushni --fastfast: pm mode versus fast mode insidehnicompare: a small CLI-focused comparison against Antfu'sniruntime: a side-by-side look athni, bun, and deno on a couple of task-style cases
The repo keeps the curated snapshot files rather than every intermediate result. For the current tracked result, use benchmark/LATEST.md.