Managed runtimes
How LPM CLI detects, installs, and exposes managed Node.js and Bun runtimes.
LPM CLI manages project runtimes itself. It detects the versions your project asks for, downloads missing installs on demand, stores them under ~/.lpm/runtimes/, and prepends the right bin/ directories to PATH for every script you run.
Node and Bun are supported managed runtimes. Deno is still unsupported.
Detection Order
When lpm run, lpm dev, lpm <file> / lpm exec, lpm test, or lpm bench starts, LPM CLI resolves managed runtime pins in deterministic order: Node first, then Bun.
Node
| Priority | Source | Format |
|---|---|---|
| 1 | lpm.json > runtime.node | Semver: ">=22.0.0", "22.5.0", "22" |
| 2 | .nvmrc | Plain version: 22.5.0, lts/iron, v22 |
| 3 | .node-version | Plain version |
| (fallback) | None of the above | Use the first Node on the constructed script PATH — no managed runtime |
.nvmrc lives in this list intentionally — projects migrating from nvm get Node pinning for free without writing lpm.json. New projects should prefer lpm.json > runtime.node because it sits next to the rest of the LPM CLI config.
Bun
| Priority | Source | Format |
|---|---|---|
| 1 | lpm.json > runtime.bun | Exact, latest, v1.3.14, bun-v1.3.14, prefix, or range |
| (fallback) | No runtime.bun declared | Do not prepend managed Bun |
package.json > engines.bun is recognized as a compatibility warning, but LPM CLI does not enforce it and does not use it as a managed-runtime pin. Use lpm.json > runtime.bun when scripts need Bun available.
Auto-Install
If a runtime selector is not already installed, LPM CLI downloads it before running the script unless auto-install is disabled:
LPM_NO_AUTO_INSTALL=true lpm devLPM_NO_AUTO_INSTALL=true applies to Node and Bun selectors. When auto-install is off and a managed runtime is missing, LPM CLI warns and leaves the system PATH in place for that runtime. It has no effect on package.json > engines.node, because an engine constraint never triggers installation.
Node releases come from https://nodejs.org/dist/index.json, cached for 1 hour at ~/.lpm/runtimes/index-cache.json. Downloads are SHA-256 verified against the matching SHASUMS256.txt entry.
Bun releases come from the GitHub releases API for oven-sh/bun, cached for 1 hour at ~/.lpm/runtimes/bun-index-cache.json. Downloads use Bun's platform asset names such as darwin-aarch64, linux-x64-musl, linux-x64-baseline, and windows-x64. Downloads are SHA-256 verified against GitHub asset digests and/or SHASUMS256.txt; when both are present, both must verify.
Storage Layout
~/.lpm/runtimes/
├── node/
│ └── 22.12.0/
│ └── bin/
│ ├── node
│ ├── npm
│ └── npx
├── bun/
│ └── 1.3.14/
│ └── bin/
│ └── bun
├── index-cache.json
└── bun-index-cache.jsonEach version is installed once and reused by every project on the machine. LPM_HOME=<path> moves the entire LPM CLI root, including runtimes/, which is useful for hermetic CI.
Concurrent projects can request the same missing runtime. LPM CLI serializes that version's installation. It publishes only a complete runtime directory.
Other projects then reuse that installation.
Script PATH Order
When a script runs, LPM CLI builds PATH from:
- Project-local
node_modules/.bin/ - Managed Node
bin/, if a Node pin resolves to an installed version - Managed Bun
bin/, ifruntime.bunresolves to an installed version - The inherited
PATH
This means locally-installed CLIs win over managed runtime tools, and managed Node wins over managed Bun when both provide a command with the same name.
runtime.bun only exposes bun to scripts. It does not switch LPM CLI script execution to bun run.
For workspace runs and multi-service dev sessions, each member or service resolves selectors from its directory. A local selector replaces the same root runtime.
The member or service inherits each unselected root runtime. For example, a service can inherit root Node and select its own Bun version.
Node Engine Enforcement
The workspace root's engines.node is a compatibility constraint, never a runtime selector. LPM CLI first applies lpm.json > runtime.node, .nvmrc, or .node-version. It then constructs the same PATH scripts receive—project and workspace node_modules/.bin directories, the selected managed runtime, then inherited PATH—and validates the first Node resolved from it against engines.node.
For workspace runs, LPM CLI resolves the local Node selector for each runnable member. It validates the first Node on that member's script PATH.
The validation uses the root and member constraints. Members without the requested task are skipped without runtime preparation.
For multi-service dev sessions, LPM CLI applies the same rule to each service cwd. Runtime validation finishes before LPM CLI starts the service set.
An engine range never selects another installed managed runtime, downloads Node, or prepends a different Node to PATH. This preserves externally selected runtimes in CI matrices. If no Node is available, the engine check fails with the declared constraint and an explicit lpm use node@<version> hint. package.json > lpm > engineStrict: false and ~/.lpm/config.toml > engine-strict = false retain warning-only behavior.
Root constraints gate lpm run, lpm install, lpm rebuild, and lpm add. Selected dependencies' engines.node ranges are install-time enforcement only: required mismatches abort, optional-only incompatible packages are skipped, and the ranges are persisted for lockfile replay.
$ lpm install
Error: lpm::engine_mismatch
× node version 18.20.4 does not satisfy required >=22.0.0 (from package.json
│ > engines.node (compared against script PATH))Resolution: select a matching managed runtime (lpm use node@22), provide a compatible Node on PATH, or relax the constraint.
engines.bun is not enforced in this first Bun runtime pass. Put the desired Bun version in lpm.json > runtime.bun to manage Bun availability.
lpm use
lpm use node@22 # install the latest 22.x, pin in lpm.json
lpm use node@lts # install latest Node LTS
lpm use bun@1.3.14 # install + pin Bun
lpm use bun@latest # install + pin latest Bun
lpm use --list bun # list installed Bun versions
lpm use remove bun@1.3 # remove all installed 1.3.x Bun runtimeslpm use <runtime>@<spec> writes the resolved version into lpm.json > runtime.<runtime>.
During a fresh install, the human output shows the resolved version, downloaded size, SHA-256 verification, extraction/linking, final runtime, and PATH hint.
lpm use <runtime>@<spec> --pin skips the download step. If the spec already matches an installed runtime, LPM CLI writes that exact installed version; otherwise it records the requested spec unchanged so a later lpm dev / lpm run can resolve or auto-install it.
lpm use remove <runtime>@<spec> deletes installed managed runtimes matching the spec without changing lpm.json. If the project still pins a matching runtime, LPM CLI warns because later commands can auto-install it again.
Compatibility With nvm / fnm
LPM CLI's Node management is independent. If you have nvm or fnm installed:
- They modify
PATHin your shell, affectingnodelookup outside LPM CLI. - LPM CLI's Node detection respects
.nvmrc, so a project pinned vianvmworks under LPM CLI without converting. - When LPM CLI runs a script with a managed Node pin, LPM CLI's runtime takes precedence over whatever
nvmset in the shell.
You do not have to remove nvm to adopt LPM CLI. If a project has both .nvmrc and lpm.json > runtime.node, the lpm.json value wins.
See Also
lpm use— install + pin commandlpm.jsonruntime — config field reference- Environment variables —
LPM_NO_AUTO_INSTALL lpm dev— picks up runtime pins automaticallylpm doctor— checks managed runtime state