Skip to content

Repository files navigation

Driftr

Driftr

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.

CI codecov Go version latest release MIT license


Why Driftr?

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, yarn, and bun from a single CLI
  • Shim-based -- node, npm, npx, pnpm, pnpx, yarn, and bun just work, resolved per-project or globally
  • Fast -- near-zero overhead via syscall.Exec process replacement
  • Minimal -- 2 external dependencies (cobra + toml), everything else is Go stdlib
  • Deterministic -- explicit resolution chain: DRIFTR_<TOOL> (one shell, via driftr use) > project config > package.json (driftr key, then packageManager field for pnpm/yarn/bun) > .nvmrc / .node-version (node) > package.json engines.node (node) > global default
  • nvm-compatible pins -- .nvmrc and .node-version are read as they are, including the lts, lts/* and lts/<codename> aliases
  • Secure -- SHA256 and SHA-512 SRI checksum verification on every download
  • Simple -- a handful of commands cover the entire workflow

Install

Homebrew (macOS and Linux)

brew tap StackMade/driftr
brew install driftr

After 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.

Quick Install (curl)

curl -fsSL https://raw.githubusercontent.com/StackMade/driftr/main/install.sh | sh

This downloads the latest release, verifies its checksum, and configures your PATH automatically. See docs/installation.md for all installation methods.

Quick Start

# In a repo that already pins its tools, install what it asks for
driftr install

# Or install tools by name
driftr install node@22
driftr install pnpm@9
driftr install yarn@1
driftr install bun@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

Commands

Command Description
driftr install [tool[@version]] Download and install a tool version (node, pnpm, yarn, bun); with no argument, installs everything the current project pins; a bare tool name installs the latest; node@lts installs the newest LTS release, node@lts/jod a named LTS line
driftr uninstall <tool@version> Remove an installed tool version
driftr prune [--dry-run] [-y] [--tool <name>] Remove installed versions that neither the global default nor the current project uses
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 use <tool@version> Print a shell snippet pinning a version for the current shell: eval "$(driftr use node@24)"
driftr list [tool] List installed versions (defaults to node)
driftr list --remote [tool] Browse available remote versions from nodejs.org, the npm registry, or bun's GitHub releases
driftr outdated Compare the versions in use against the newest releases upstream
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; --fix repairs PATH and shims
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.

Shared dependency storage (driftr node)

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 packages

optimize is idempotent — already-correct settings are left untouched — and requires pnpm (run corepack enable first if it is missing).

Remote version listing flags

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).

Checking for updates (driftr outdated)

driftr outdated                # every managed tool
driftr outdated --tool node    # just one
driftr outdated --pre          # include npm pre-releases
driftr outdated --exit-code    # exit 1 when something is behind (CI)

The report shows the version each tool resolves to, the newest release on that major line, the newest release overall, and for node the newest LTS. A tool whose release source cannot be reached is reported as unknown and does not stop the rest of the report.

Shell Completions

# zsh
echo 'eval "$(driftr completion zsh)"' >> ~/.zshrc

# bash
echo 'eval "$(driftr completion bash)"' >> ~/.bashrc

# fish
driftr completion fish | source

How It Works

flowchart TD
    A["$ node app.js"] --> B["shim (bin/)"]
    B --> C["resolver"]
    C --> C1["1. explicit flag"]
    C --> C1b["2. DRIFTR_NODE env var\n(set by driftr use)"]
    C --> C2["3. .driftr.toml\n(walks up dirs)"]
    C --> C3["4. package.json driftr key\n(walks up dirs)"]
    C --> C4["5. .nvmrc (node only)\n(walks up dirs)"]
    C --> C5["6. .node-version (node only)\n(walks up dirs)"]
    C --> C6["7. package.json engines.node\n(node only, newest installed match)"]
    C --> C7["8. global config.toml"]
    C --> C3b["4b. package.json packageManager field\n(pnpm/yarn/bun only, walks up dirs)"]
    C1 & C1b & C2 & C3 & C3b & C4 & C5 & C6 & C7 --> D["syscall.Exec\nreplaces process with real node"]
Loading

Shims in ~/.driftr/bin/ intercept calls to node, npm, npx, pnpm, pnpx, yarn, and bun. The resolver determines the correct version, and syscall.Exec replaces the process with the real binary. Standalone tools (node, pnpm, bun) are exec'd directly. Tools that need Node.js (yarn) are exec'd as node <tool-script>.

Documentation

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

Project Layout

~/.driftr/
  bin/              shims (node, npm, npx, pnpm, pnpx, yarn, bun)
  tools/
    node/           installed Node.js versions
    pnpm/           installed pnpm versions
    yarn/           installed yarn versions
    bun/            installed bun versions
  config/
    config.toml     global default settings
  cache/            downloaded archives + binaries

How Driftr Compares

Driftr nvm Volta fnm mise
Language Go Shell Rust Rust Rust
Mechanism Shims Shell function Shims PATH via shell hook PATH via shell hook (shims optional)
Cost model ~5ms per tool call, nothing at shell startup 200-500ms per shell startup per tool call per prompt / directory change per prompt / directory change
Direct dependencies 2 (cobra, toml) 0 (shell) 12 27 79
Tools managed node, npm, npx, pnpm, pnpx, yarn, bun node + its bundled npm node, npm, yarn; pnpm experimental (VOLTA_FEATURE_PNPM=1) node only node, pnpm, yarn, bun + hundreds of others
Reads .nvmrc / .node-version Yes Yes No Yes Yes
Reads engines.node Yes (installed versions) No No Yes (default on) No
Reads packageManager Yes (pnpm, yarn, bun) No No Via corepack Via corepack
Checksum verification Always: SHA-256 (node, bun), SHA-512 SRI (pnpm, yarn) Yes, SHA-256 No No Opt-in via mise.lock
Auto-install a missing pinned version Yes, on shim call (prompt, or auto_install = true) No Yes --install-if-missing Yes
macOS / Linux Yes Yes Yes Yes Yes
Windows No No Yes Yes Yes
Latest release v1.1.0 (2026-08) v0.40.7 (2026-08) v2.0.2 (2024-12) v1.39.0 (2026-03) v2026.9.1 (2026-09)
Maintained Yes Yes No (upstream says so) Yes Yes
Self-update driftr self-update nvm install script No Package manager mise self-update

Verified against upstream repositories and documentation on 2026-09-07. Dependency counts are direct dependencies from each project's manifest, not the transitive tree. The Driftr cost figure is the measured gap between running ~/.driftr/bin/node -v and calling the real node binary on an Apple Silicon Mac. It is per-call overhead, so you pay it when you run a tool and never when you open a shell.

When to choose Driftr: You want a shim-based manager for Node.js, pnpm, yarn and bun that behaves the way Volta did: pin a version to a project, and the tools follow. Driftr adds nothing to your shell startup, so the same pins hold in scripts, cron jobs and CI without an activate step. It checks the checksum of every download before unpacking it, ships with two library dependencies, and driftr node can point pnpm at one shared store instead of a separate node_modules copy per project.

When to choose something else: fnm if you need Windows. mise if you want one tool for Node, Python, Ruby and everything else; Volta's own README now sends people there. nvm if it already works for you and shell startup time doesn't bother you.

Requirements

  • macOS or Linux
  • curl or wget (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)

About

StackMade

Built by StackMade - a family of small, focused tools shipped as code-first products.

Maintained by Krzysztof Słomka, software architect specializing in fintech, distributed systems and event-driven architectures.

License

MIT

Contributing

See docs/contributing.md for guidelines on how to contribute.

About

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.

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages