nhx - Node.js Hybrid eXecutor (a uvx inspired tool)
A hybrid of node ./script.js and npx package - run scripts or packages with automatic dependency handling.
Why nhx?
- Self-contained scripts - Scripts declare their own dependencies and just work
-
No project setup - No
package.json, nonpm install, nonode_modules - Share scripts easily - Send a single file that anyone can run
- Fast - Dependencies are cached globally, subsequent runs are instant
- Works offline - Once cached, no network needed
Options
--with <dep> Add a dependency (repeatable, supports @version)
--engine <spec> Node version (e.g. node:18, node:>=16)
--run-postinstall Allow postinstall scripts (disabled by default)
-h, --help Show help
All other flags pass through to node.
Examples
# Run an npm package nhx cowsay hello # Run a local script (dependencies installed automatically) nhx ./script.js # Add a dependency for a script nhx --with=lodash ./script.js # Pin a specific version nhx --with=chalk@4.1.2 ./script.js # Use a specific node version nhx --engine=node:18 ./script.js # Pipe from stdin curl -s https://example.com/script.js | nhx - # All node flags work nhx -e 'console.log(1)' nhx --check ./script.js
Self-contained scripts
Scripts can declare their own dependencies inline:
// hello.mjs /*/ // <package> { dependencies: { chalk: "^5.0.0" } } /*/ // </package> import chalk from 'chalk'; console.log(chalk.green('Hello!'));
Dependencies are installed automatically on first run and cached for future runs.
Specifying a node version
/*/ // <package> { engines: { node: ">=18 <21" } } /*/ // </package> console.log(process.version);
If your current node satisfies the range, it's used directly. Otherwise nhx downloads an appropriate version.
Loaders
Use tsx as a declared dependency and as a loader:
#!/usr/bin/env -S nhx --with=tsx --import tsx import { something } from './other.ts';
You can also do that with inline dependencies:
#!/usr/bin/env -S nhx --import tsx /*/ // <package> { devDependencies: { tsx: "^4" } } /*/ // </package>
License
MIT