Fast JavaScript toolchain versioning without the friction.
A lightweight JavaScript toolchain manager built for speed and simplicity.
The spiritual successor to Volta, made for developers by developers.
Volta is no longer maintained. If you liked Volta's "pin and forget" model -- where node, pnpm, and yarn just work without manual switching -- Driftr carries that torch forward.
Driftr is a new project. It doesn't have Volta's years of polish or fnm's community size. But it has a clean foundation, an honest design, and an active maintainer who actually uses it. If you're looking for something simple that does the job, give it a try. If it's missing something you need, open an issue -- we're listening.
- Multi-tool -- manages Node.js, pnpm, and yarn from a single CLI
- Shim-based --
node,npm,npx,pnpm,pnpx, andyarnjust work, resolved per-project or globally - Fast -- near-zero overhead via
syscall.Execprocess replacement - Minimal -- 2 external dependencies (cobra + toml), everything else is Go stdlib
- Deterministic -- explicit resolution chain: project config >
package.json(driftrkey, thenpackageManagerfield for pnpm/yarn) >.nvmrc/.node-version(node) > global default - Secure -- SHA256 and SHA-512 SRI checksum verification on every download
- Simple -- a handful of commands cover the entire workflow
brew tap StackMade/driftr
brew install driftrAfter installing, run driftr setup — it generates the shims and configures your shell PATH automatically (writing to a universally-sourced rc file such as ~/.zshenv). Restart your shell afterwards. See docs/installation.md for details and why PATH ordering matters on macOS.
curl -fsSL https://raw.githubusercontent.com/StackMade/driftr/main/install.sh | shThis downloads the latest release, verifies its checksum, and configures your PATH automatically. See docs/installation.md for all installation methods.
# Install your toolchain
driftr install node@22
driftr install pnpm@9
driftr install yarn@1
# Set global defaults
driftr default node@22.22.0
driftr default pnpm@9.15.0
# Pin a project (prompts for .driftr.toml or package.json on first use)
cd my-project
driftr pin node@22.22.0
driftr pin pnpm@9.15.0
# Everything just works
node -v # resolves automatically
pnpm -v # resolves automatically| Command | Description |
|---|---|
driftr install <tool[@version]> |
Download and install a tool version (node, pnpm, yarn); a bare tool name installs the latest; node@lts installs the newest LTS release |
driftr uninstall <tool@version> |
Remove an installed tool version |
driftr default <tool@version> |
Set the global default version for a tool |
driftr pin <tool@version> |
Pin a version to the current project (.driftr.toml or package.json) |
driftr list [tool] |
List installed versions (defaults to node) |
driftr list --remote [tool] |
Browse available remote versions from nodejs.org / npm registry |
driftr which <tool> |
Show which binary would be executed and why |
driftr run --node <ver> -- <cmd> |
Run a command under a specific Node.js version |
driftr setup |
Initialize Driftr, generate shims, and configure your shell PATH |
driftr cache clean |
Remove all cached downloads to free disk space |
driftr cache dir |
Print the cache directory path |
driftr self-update |
Update Driftr to the latest version |
driftr doctor [--fix] |
Check your Driftr installation for common problems |
driftr node doctor |
Analyze the project's Node.js / pnpm dependency environment |
driftr node optimize [--install] |
Configure pnpm for shared dependency storage (idempotent) |
driftr node clean [--yes] |
Remove node_modules and prune the shared store (dry-run by default) |
driftr node report |
Report node_modules size and shared pnpm store size |
All commands support -v / --verbose for detailed output including resolver tracing and checksum details.
Output is colorized when writing to a terminal. Color is disabled automatically when output is piped/redirected, or when the NO_COLOR environment variable is set.
Driftr does not replace pnpm/npm/yarn. The driftr node commands configure and
maintain pnpm's shared content-addressable store so dependencies are stored once
and reused across every project on the machine, instead of duplicated in each
node_modules.
driftr node doctor # see current package manager + pnpm store configuration
driftr node optimize # enable corepack, point pnpm at ~/.driftr/stores/pnpm,
# and turn on the global virtual store
driftr node report # compare project node_modules size vs shared store size
driftr node clean # dry-run: show what would be removed/pruned
driftr node clean --yes # remove node_modules, reinstall, prune orphaned packagesoptimize is idempotent — already-correct settings are left untouched — and
requires pnpm (run corepack enable first if it is missing).
driftr list --remote [tool] # Show available versions (default: latest 30)
driftr list --remote --limit 10 # Limit output to 10 versions
driftr list --remote --limit 0 # Show all versions (can be 500+ for node)
driftr list --remote --pre pnpm # Include pre-release versions (npm packages only)Installed versions are marked with ●, the active version with >, and the global default with *. Node.js LTS releases show their codename (e.g. LTS: Jod).
# zsh
echo 'eval "$(driftr completion zsh)"' >> ~/.zshrc
# bash
echo 'eval "$(driftr completion bash)"' >> ~/.bashrc
# fish
driftr completion fish | sourceflowchart TD
A["$ node app.js"] --> B["shim (bin/)"]
B --> C["resolver"]
C --> C1["1. explicit flag"]
C --> C2["2. .driftr.toml\n(walks up dirs)"]
C --> C3["3. package.json driftr key\n(walks up dirs)"]
C --> C4["4. .nvmrc (node only)\n(walks up dirs)"]
C --> C5["5. .node-version (node only)\n(walks up dirs)"]
C --> C6["6. global config.toml"]
C --> C3b["3b. package.json packageManager field\n(pnpm/yarn only, walks up dirs)"]
C1 & C2 & C3 & C3b & C4 & C5 & C6 --> D["syscall.Exec\nreplaces process with real node"]
Shims in ~/.driftr/bin/ intercept calls to node, npm, npx, pnpm, pnpx, and yarn. The resolver determines the correct version, and syscall.Exec replaces the process with the real binary. Standalone tools (node, pnpm) are exec'd directly. Tools that need Node.js (yarn) are exec'd as node <tool-script>.
| Document | Description |
|---|---|
| Installation | Detailed install guide for macOS and Linux |
| Usage | Full CLI reference with examples |
| Configuration | Global and project config format |
| Architecture | Internal design and module overview |
| Contributing | How to contribute to the project |
~/.driftr/
bin/ shims (node, npm, npx, pnpm, pnpx, yarn)
tools/
node/ installed Node.js versions
pnpm/ installed pnpm versions
yarn/ installed yarn versions
config/
config.toml global default settings
cache/ downloaded archives + binaries
| Driftr | nvm | Volta | fnm | mise | |
|---|---|---|---|---|---|
| Language | Go | Shell | Rust | Rust | Rust |
| Mechanism | Shims | Shell function | Shims | PATH manipulation | PATH manipulation |
| Shell startup cost | ~1ms | 200-500ms | ~1ms | ~1ms | ~5ms |
| External dependencies | 2 | 0 (shell) | ~36 crates | 24 crates | 113 crates |
| macOS / Linux | Yes | Yes | Yes | Yes | Yes |
| Windows | No | No | Yes (rough) | Yes | Very basic |
| Manages npm/pnpm/yarn | Yes | No | Partial | No | Yes |
| Maintained | Yes | Yes | No | Yes | Yes |
| Self-update | driftr self-update |
nvm script |
No | No | mise self-update |
When to choose Driftr: You want a fast, minimal, shim-based manager for Node.js, pnpm, and yarn with a Volta-like experience -- pin versions to projects, and tools just work. You value simplicity and a small dependency footprint.
When to choose something else: If you need Windows support, fnm is your best bet. If you want one tool for Node + Python + Ruby + everything else, mise is the polyglot option. If nvm already works for you and startup time doesn't bother you, there's no reason to switch.
- macOS or Linux
curlorwget(for the install script)- Internet access (to download releases from nodejs.org, GitHub, and the npm registry)
- Go 1.26+ (only if building from source)
MIT
See docs/contributing.md for guidelines on how to contribute.
