Compared to npm, pnpm, bun
Side-by-side defaults across the four JavaScript package managers — security, resolution, developer orchestration, publishing, and platform.
A factual comparison of default behavior across npm, pnpm, bun, and lpm.
Install benchmarks use the tracked VitePress docs fixture, a real-world workspace graph with 535 packages.
| Benchmark | npm | pnpm | bun | lpm | lpm + LPM Firewall monitor |
|---|
| Cold install, equal footing ¹ | 17,354ms | 6,125ms | 2,455ms | 2,945ms | 3,043ms |
| Warm install ¹ | 3,819ms | 3,301ms | 451ms | 387ms | 324ms |
| Up-to-date install ¹ | 282ms | 522ms | 77ms | 14ms | 14ms |
Dev command benchmarks measure already-installed local scripts, local bins, and built-in tools.
| Benchmark | npm / npx / tsx | pnpm | bun / bunx | lpm |
|---|
| Trivial echo script ² | 74ms | 161ms | 15ms | 10ms |
| Node startup + tiny script ² | 101ms | 185ms | 33ms | 27ms |
Local bin: esbuild --version ² | 144ms | 174ms | 27ms | 21ms |
| Run TSX app, warm cache ³ | 112ms | — | 19ms | 41ms |
lpm lint vs npx oxlint ⁴ | 273ms | — | — | 3ms |
lpm fmt vs npx biome ⁴ | 340ms | — | — | 3ms |
| Axis | npm | pnpm | bun | lpm |
|---|
| Dependency lifecycle-script sandbox | — | — | — | Dependency lifecycle-script sandbox: approved or triage-selected dependency scripts run under macOS Seatbelt, Linux Landlock, or Windows AppContainer. Default mode contains filesystem access while allowing network. Strict mode denies outbound network on macOS and AppContainer; Linux 6.7+ uses Landlock V4 plus seccomp, with AF_UNIX retained for IPC. Older Linux kernels and Windows installs missing the AppContainer helper refuse strict mode unless allow-degraded = true. Root-project lifecycle scripts are not sandboxed. |
Dependency lifecycle scripts (preinstall / install / postinstall) | All scripts run | Blocked until approved (approve-builds flow) | Blocked unless in trustedDependencies; bun ships a built-in 367-package default trusted list that also runs scripts without approval | Dependencies are blocked by default. Under the opt-in triage policy, green verdicts are eligible to auto-run in the sandbox; an optional advisor can approve amber verdicts for the current run; red verdicts remain blocked. The root project's lifecycle runs on bare lpm install without the dependency sandbox. |
| Registry package signatures | Manual via npm audit signatures | Manual via pnpm audit signatures | — | lpm audit signatures; optional install-time fail-closed verification with lpm config signatures --set true |
| Sigstore provenance verification | Publish-time provenance support | Publish-time provenance support | — | DSSE + Rekor body + Rekor SET + SCT + X.509 chain verified end-to-end on install for provenance bundles served by npmjs |
| Minimum release age (cooldown) | min-release-age flag, off by default | 1-day cooldown by default | Off by default | Off by default; configurable direct/root or strict transitive cooldown |
engines.node enforcement | Warn only | Warn only | — | Validates the selected or PATH Node without installing or switching runtimes; hard-fails missing/incompatible required constraints, skips optional-only incompatible packages, persists dependency constraints for warm/frozen/offline replay, and supports warning-only opt-out |
| Built-in vulnerability audit | npm security database | Registry-side data | Proxies to npm audit endpoint | OSV + behavioral analysis + verdict cache |
| Approval-gated weakening of security posture | — | — | — | Weaker CLI flags can require native approval; pulled repo or config-file weakenings are treated as proposals until a short-lived unlock or persistent signed machine approval exists |
| Provenance drift detection on republish | — | Resolve-time trust-rank downgrade refusal (trustedPublisher → provenance → none) | — | Detects publisher-identity drift for stored rich trust bindings; optional trust-policy = "no-downgrade" refuses weaker npm publish trust during resolution and requires continued artifact verification after verified lockfile history |
| Pluggable third-party security scanner protocol (register an npm package as a scanner, run it against the lockfile) | — | — | bunfig.toml > [install.security] scanner = "<pkg>", invoked by bun pm scan | — (built-in triage + audit cover a different surface; not pluggable) |
| Axis | npm | pnpm | bun | lpm |
|---|
| Resolver | Arborist backtracking | Highest-version + workspace-rooted peer resolution | Tree resolution + backtracking | Greedy-fusion (PubGrub legacy arm available) |
| Package store | Content-addressable cache | Content-addressable, versioned virtual store | Content-addressable, hardlinked | Content-addressable virtual store; copy-on-write clone/reflink where available, independent-copy fallback |
node_modules layout | Hoisted | Isolated (symlinked virtual store) | Auto: hoisted for single-package, isolated when workspaces detected | Auto: v2 hoisted virtual-store for single packages, isolated for workspaces or default peer-conflict installs |
| Phantom-dependency prevention | Hoisted layout leaks unlisted deps | Isolated by default | In isolated mode | In isolated mode (default for workspaces and peer-conflict installs) |
| Lockfile | package-lock.json v3 | pnpm-lock.yaml v9 | bun.lock (JSONC) | lpm.lock (TOML, authoritative) plus lpm.lockb binary companion when the graph fits the binary format |
| Patched dependencies | — | pnpm patch workflow | bun patch workflow | Native patchedDependencies; reads pnpm's shape for migration |
| Dependency overrides | Yes (overrides field, npm 8+) | Yes | Yes | Honors top-level npm overrides, Yarn resolutions, and lpm.overrides; lpm migrate translates pnpm.overrides |
| Native dependency build-artifact cache | — | Side-effects cache, enabled by default | — | Automatic for eligible strict-sandbox builds on macOS and Linux; content-addressed artifacts are reused only when package graph, platform, Node runtime/ABI, environment, sandbox, and toolchain inputs match |
This is the most lopsided table — three of the four columns are blank for several rows.
| Axis | npm | pnpm | bun | lpm |
|---|
| Secrets vault (E2E-encrypted, secure-store preferred, cloud sync) | — | — | Auto-loads .env, no vault | Per-project and per-environment; prefers the OS secure store with encrypted-file fallback; org sharing, OIDC CI escrow, and client-direct Vercel, Coolify, Fly.io, Railway, and GitHub Actions integrations |
| Zero-config dev server orchestrator | — | — | — | Auto-installs stale deps, loads env, starts services, opens the browser when ready, and starts LPM CLI's browser webhook inspector when tunneling |
| Remote task cache | Use Turborepo / Nx | Use Turborepo / Nx | Use Turborepo / Nx | Local task cache + hosted remote cache; content hashes always, optional HMAC signing via remoteCache.signature, read-only mode, quota / usage status, and env-policy upload guards |
| Local HTTPS with dev-only certificate authority | Use mkcert | Use mkcert | Use mkcert | Built-in CA: status / trust / uninstall / generate. Picked up automatically by the dev server. |
| Local tunneling (public URL to localhost) | Use ngrok | Use ngrok | Use ngrok | Stable claimable domains, webhook capture, replay, and audit log |
| Managed runtime availability | — | Node version pinning | Bun is its own runtime | Auto-installed Node and Bun via lpm.json > runtime; Node also falls back through .nvmrc and .node-version |
| Managed linter / formatter | — | — | Formatter exists in the runtime, not the install surface | oxlint + biome as lazy-downloaded plugins, pinned via lpm.json > tools |
| One-off package execution (npx-equivalent) | npx, permanent cache | pnpm dlx, 1-day cache | bunx | lpm dlx / lpx, 1-day cache |
| Built-in bundler | — | — | Yes | No native bundler; lpm bundle uses managed Rolldown, while lpm pack wraps project-local tsdown |
| Built-in test runner | — | — | Yes | No native test engine; lpm test orchestrates Vitest / Jest / Mocha |
| Axis | npm | pnpm | bun | lpm |
|---|
| Source-code delivery (copy package files into the project, shadcn-style) | — | — | — | lpm add — works for any tarball-shipped package on any reachable registry (lpm.dev, npm, private via .npmrc) |
| Dependency selector queries (CSS-like syntax over behavioral tags) | — | — | — | lpm query — :eval, :scripts:not(:built), :root > :network, #express, --assert-none CI gate |
| Dependency-graph visualization | npm ls (text) | pnpm list (text) | bun pm ls (text) | lpm graph / lpm ls — HTML / JSON / dot output, depth filter, lpm why <pkg> reverse-lookup |
| Interactive upgrade picker | — | pnpm update -i | bun update --interactive | lpm upgrade [pkg...] (interactive by default on TTY) — targeted upgrades, peer-impact analysis |
| License inventory and policy gate | third-party tooling | third-party tooling | third-party tooling | lpm licenses — local inventory, --fail-on copyleft,missing, exact --deny <LICENSE> gates |
Programmable resolution hooks (intercept readPackage / afterAllResolved at resolve time) | — | .pnpmfile.cjs | — | — |
| Install-time policy extensions | — | — | — | Local package.candidate extensions evaluate resolved packages before fetch/link and return allow, warn, or block; they do not mutate resolution |
| Workspaces (monorepo) | --workspace selector | Rich --filter pattern syntax | --workspace, --all-workspaces | pnpm-style filter grammar |
| Catalog version pins for monorepos (one declaration, every member references it) | — | pnpm-workspace.yaml > catalog | Catalogs in lockfile | package.json > catalogs, plus pnpm-style pnpm-workspace.yaml catalogs and cleanup |
| Workspace-package deploy (extract one member + transitive deps to a deployable dir) | — | pnpm deploy | — | lpm deploy |
| Migration from other package managers | — | — | Reads npm + yarn lockfiles | One-command lockfile migration from npm / pnpm / Yarn / Bun; pnpm migration also translates overrides, patches, and peer rules |
| Swift Package Manager (SE-0292) | — | — | — | SE-0292-compatible after LPM CLI configures the scope; certificate/trust setup occurs on the first Swift install; CMS signing is available on a best-effort basis |
| Axis | npm | pnpm | bun | lpm |
|---|
| First-party hosted registry | npmjs.org (public and private packages) | — | — | LPM.dev Registry: private by default, with Pool and Marketplace as explicit opt-ins. Every upload gets validation, quality scoring, OSV vulnerability scanning where dependency data is available, and distribution checks. Pool and Marketplace versions stay pending until mandatory AI publication review approves them, then queue API-doc extraction and optional AI enrichment; private versions are excluded from AI/enrichment processing. |
| Sigstore provenance signing on publish | --provenance flag | Auto in CI when OIDC available | — | --provenance flag + auto-OIDC token exchange |
| OIDC trusted-publisher token exchange | GitHub Actions | GitHub Actions + GitLab CI | — | GitHub Actions + GitLab CI |
| 2FA on publish | OTP | OTP | --otp flag | OTP |
.npmrc scope-to-registry routing | Yes | Yes | Yes | Yes — mappings are honored for npm-compatible private registries and JSR mirrors; per-origin authentication is supported |
| Auth-token storage | .npmrc plain text | .npmrc plain text | .npmrc / bunfig.toml plain text | OS keychain preferred; AES-256-GCM encrypted-file fallback; .npmrc honored for compatibility |
| Default registry routing | npmjs.org | npmjs.org | npmjs.org | npm packages go directly to npmjs.org; native jsr: dependencies go to npm.jsr.io; only @lpm.dev/* always routes through lpm.dev |
| Axis | npm | pnpm | bun | lpm |
|---|
| macOS (Intel + Apple Silicon) | Yes | Yes | Yes | Yes |
| Linux (glibc) | Yes | Yes | Yes | Yes |
| Linux (musl / Alpine) | Yes | Yes | Yes | Yes — official x64 binary through npm, the standalone installer, and GitHub Releases; ARM64 requires a source build |
| Windows x64 | Yes | Yes | Yes | Yes |
| FreeBSD | Yes | Yes | — | — |
| Self-update | npm install -g npm | pnpm self-update | bun upgrade | lpm self-update — install-method-aware (npm / Homebrew / Cargo / standalone GitHub Releases); 24-hour banner check |
| Implementation language | JavaScript (Node.js) | TypeScript (Rust port underway) | Zig (Rust port underway) | Rust |