snpmv2026.5.16

Basic Usage

The day-to-day snpm workflow

snpm is shaped like pnpm with familiar npm-style ergonomics. The same package.json works as-is.

Install dependencies

snpm install

Reads package.json, resolves the dependency graph, materializes packages into the shared store, and links them into node_modules/.snpm plus the root node_modules tree.

Useful flags:

  • --production — skip devDependencies.
  • --frozen-lockfile (alias --immutable) — fail if the lockfile is missing or out of date.
  • --no-frozen-lockfile — ignore the lockfile and re-resolve.
  • --prefer-frozen-lockfile — reuse the lockfile when valid, otherwise re-resolve.
  • --fix-lockfile — re-resolve drifted entries while preserving the rest.
  • -f, --force — ignore cached state and force a full install.
  • -w, --workspace <name> — target a single workspace project from the workspace root.
snpm install --production --frozen-lockfile   # CI / production
snpm install --fix-lockfile                   # repair lockfile drift
snpm install -w @acme/api                     # workspace-scoped install

The --frozen-lockfile, --no-frozen-lockfile, and --prefer-frozen-lockfile flags can also be set globally before the subcommand (snpm --frozen-lockfile install) and they propagate to any install-like command (add, remove, upgrade, run, exec).

Add and remove

snpm add react                  # latest matching version
snpm add react@18.2.0           # exact version
snpm add -D typescript          # devDependency
snpm add react react-dom        # multiple packages

snpm remove react
snpm remove -g create-react-app

add and remove accept the same workspace selectors as the rest of the CLI: -w <name>, -r/--recursive, --filter <selector>, and --filter-prod <selector>.

Run scripts

snpm run build              # one-off
snpm run test -- --watch    # pass args after --
snpm build                  # script-name fallback (unknown subcommands)

Scripts auto-trigger a lazy install if package.json or snpm-lock.yaml has drifted from node_modules. Pass --skip-install to bypass that check.

Workspace selectors:

snpm run build -r                          # every project
snpm run test --filter "@acme/*"           # name glob
snpm run test --filter ./packages/api      # path
snpm run test --filter api...              # api and its dependencies
snpm run test --filter ...api              # api and its dependents
snpm run test --filter "[origin/main]"     # projects changed since origin/main
snpm run test --filter "!@acme/docs"       # exclude a project

--filter-prod accepts the same selector grammar but restricts dependency/dependent walks to production dependencies only.

Execute binaries

snpm exec eslint .              # run a binary from node_modules/.bin
snpm exec -c "eslint . | head"  # shell mode for pipes/redirects
snpm exec --recursive tsc --build

One-off packages

snpm dlx cowsay "moo"             # download, run, discard
snpm dlx create-vite my-app -- --template react-ts
snpm dlx --offline tsc --version   # fail if not cached
spx cowsay "moo"                   # multicall alias for snpm dlx

snpx and pnpx are also recognized as aliases for snpm dlx, and snpr is an alias for snpm run.

Lifecycle scripts

snpm supports the standard lifecycle stages for the root project (and workspace members), running them in order during install:

  • preinstall
  • install
  • postinstall
  • prepare (after install and before publish)
{
  "scripts": {
    "preinstall": "node scripts/check-env.js",
    "install": "node-gyp rebuild",
    "postinstall": "node scripts/postinstall.js",
    "prepare": "npm run build"
  }
}

Dependency lifecycle scripts are blocked by default. To allow specific dependencies to run preinstall/install/postinstall, list them in SNPM_ALLOW_SCRIPTS=name1,name2 or the workspace onlyBuiltDependencies array. After changing the allow-list, run snpm rebuild to apply it to packages that already extracted.

Upgrade and outdated

snpm upgrade                # delete the lockfile and re-resolve to latest in range
snpm upgrade react react-dom
snpm upgrade --production
snpm upgrade -r --filter "@acme/*"

snpm outdated               # show pending updates
snpm outdated -r            # across all workspace projects

Inspection

snpm list                   # show project dependencies
snpm list -g                # show global installs
snpm licenses               # license per installed package
snpm licenses --json
snpm why typescript         # show dependency paths into typescript
snpm why "babel-*" --json   # glob support
snpm store status           # store size / package count

Performance

Hot install — when package.json and snpm-lock.yaml agree with node_modules/.snpm-integrity, install finishes in tens of milliseconds.

Warm install — when the lockfile is valid and all tarballs are in the shared store, links and integrity markers refresh in a few seconds.

Cold install — fetches go in parallel (default concurrency 128, tunable with SNPM_REGISTRY_CONCURRENCY).

Where things live

PathPurpose
<data_dir>/packages/<name>/<version>/Shared package store
<data_dir>/virtual-store/Shared .snpm entries pooled across projects
<data_dir>/global/Global installs (snpm add -g)
<data_dir>/bin/Global bin shims
<cache_dir>/metadata/Registry metadata cache
node_modules/.snpm/Project virtual store
node_modules/.snpm-integrityLockfile-derived hash for fast install detection

On macOS, cache_dir and data_dir are platform-default (~/Library/Caches/snpm, ~/Library/Application Support/io.snpm.snpm). Override with SNPM_HOME=/path/to/snpm to get cache=$SNPM_HOME/cache, data=$SNPM_HOME/data.

On this page