Lockfile
snpm-lock.yaml schema, integrity markers, and lockfile imports
snpm-lock.yaml is snpm's native lockfile. It pins the exact resolved version, tarball, and integrity hash for every package in the dependency graph, making installs deterministic across machines and CI runners.
Schema
The lockfile is YAML and currently uses schema version 1.
version: 1
root:
dependencies:
express:
requested: "^4.18.0"
version: 4.18.2
typescript:
requested: ^5.4.0
version: 5.4.5
optional: false
packages:
express@4.18.2:
name: express
version: 4.18.2
tarball: https://registry.npmjs.org/express/-/express-4.18.2.tgz
integrity: sha512-...
dependencies:
body-parser: body-parser@1.20.1
cookie: cookie@0.5.0
hasBin: false
body-parser@1.20.1:
name: body-parser
version: 1.20.1
tarball: https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz
integrity: sha512-...
dependencies: {}Key fields:
root.dependencies— direct dependencies declared inpackage.json. Each entry records the originallyrequestedrange plus the resolvedversion(andoptionalif the dep is optional).packages.<name>@<version>— the resolved package. Storesname,version,tarball,integrity, transitivedependencies(map name →name@versionof the resolved entry),bundledDependencies(if any), andhasBin/binfor packages that ship binaries.
Workspaces share a single snpm-lock.yaml at the workspace root.
When the lockfile is written
The lockfile updates whenever the install plan changes — snpm add, snpm remove, snpm upgrade, or snpm install with new packages.
snpm only writes a dev-inclusive lockfile when include_dev = true. With --production (or running an install path that skips dev), the existing lockfile is reused but not rewritten, so dev resolution does not get clobbered.
Frozen, prefer, fix
| Mode | CLI flag | Behavior |
|---|---|---|
| Frozen | --frozen-lockfile (alias --immutable), or SNPM_FROZEN_LOCKFILE=1 | Fail if the lockfile is missing or does not match the manifest. |
| No frozen | --no-frozen-lockfile | Ignore lockfile data and re-resolve. |
| Prefer | --prefer-frozen-lockfile | Reuse lockfile entries that are still valid, re-resolve the rest. |
| Fix | --fix-lockfile (install only) | Re-resolve drifted entries while keeping unchanged ones pinned. |
Pass these flags globally (snpm --frozen-lockfile install) and they propagate to every install-like subcommand, or pass them directly to the subcommand.
Integrity marker
After a successful install, snpm writes node_modules/.snpm-integrity containing a lockfile-derived hash. The next install reads this marker first and short-circuits if the hash still matches — that is the "hot install" path that completes in tens of milliseconds.
In workspaces, the integrity marker is written per project so changes to one project's deps don't invalidate the others.
Importing other lockfiles
When snpm-lock.yaml is missing, snpm can seed the first install from a compatible lockfile and then take over with its own format:
| Source | Files |
|---|---|
| pnpm | pnpm-lock.yaml, branch lockfiles like pnpm-lock.feature!name.yaml |
| Bun | bun.lock |
| Yarn | yarn.lock |
| npm | npm-shrinkwrap.json, package-lock.json |
Imported data is used only as compatibility input. Once the install completes, snpm-lock.yaml is the source of truth. Subsequent installs read snpm's lockfile.
Workspaces
A workspace has exactly one snpm-lock.yaml at the root — it covers every workspace project:
my-monorepo/
├── snpm-workspace.yaml
├── snpm-lock.yaml ← single lockfile
├── packages/
│ ├── ui/package.json
│ └── utils/package.json
└── apps/
└── web/package.jsonVersion control
Always commit snpm-lock.yaml.
It is small, human-readable, and the only guarantee that local builds match CI and production.
Merge conflicts
When you hit a conflict in snpm-lock.yaml:
- Resolve conflicts in every affected
package.jsonfirst. - Delete
snpm-lock.yaml. - Run
snpm install.
git checkout --theirs package.json apps/*/package.json
# resolve manually if needed
rm snpm-lock.yaml
snpm install
git add snpm-lock.yamlIf you want to keep the existing resolution where possible, run snpm install --fix-lockfile instead — it only re-resolves entries that drifted.
Best practices
- Always commit the lockfile.
- Use
--frozen-lockfilein CI — it catches missed commits and prevents quiet upgrades. - Review the diff in PRs — the YAML format makes it readable; new tarball URLs or integrity changes show up cleanly.
- Prefer
--fix-lockfileover deleting it when only a small subset of deps needs to be re-resolved. - Use
snpm why <pkg>to trace why an unexpected package landed in the lockfile.