lpm.lock format
TOML lockfile schema — what every field means and why it's there.
lpm.lock is the human-readable, git-diffable lockfile written next to package.json after every lpm install. It pins every transitive dependency by exact version, source registry, and SRI integrity hash, so the next install — on any machine, with any cache state — produces a byte-identical node_modules/.
The companion lpm.lockb binary lockfile holds the same data in a mmap-friendly format for zero-parse warm starts. Both files should be committed.
File location
<project-root>/lpm.lock
Top-level shape
[metadata]
lockfile-version = 2
resolved-with = "greedy-fusion"
# Only present when the default linker auto-switched to isolated
# after detecting incompatible peer requirements.
auto-isolated-peer-conflicts = true
[[packages]]
name = "react"
version = "19.0.0"
source = "registry+https://registry.npmjs.org"
integrity = "sha512-..."
dependencies = ["scheduler@0.25.0"]
tarball = "https://registry.npmjs.org/react/-/react-19.0.0.tgz"
[[packages]]
name = "scheduler"
version = "0.25.0"
source = "registry+https://registry.npmjs.org"
integrity = "sha512-..."
# Only present when at least one root dep uses npm:<target>@<range>
[root-aliases]
my-react-alias = "react"
# Only present when the eager peer-drain pass synthesized installs to
# satisfy unmet peerDependencies (default-on under autoInstallPeers).
ambient-peer-installs = ["loose-envify"][metadata]
| Field | Type | Notes |
|---|---|---|
lockfile-version | u32 | Schema version. Current: 2 (bumped from 1 when the per-entry tarball hint + peers array landed). Schema-versioned (not tool-versioned) so older clients can refuse cleanly when the schema bumps. |
resolved-with | string | Which resolver produced this file (e.g. "greedy-fusion", "pubgrub"). Informational. |
auto-isolated-peer-conflicts | bool | Present only when a default-hoisted install detected incompatible peer requirements and auto-switched the project to isolated layout. Warm installs read this before the resolver runs so the install hash and linker stay on the peer-preserving layout. Explicit linker config ignores this flag. |
[[packages]]
One entry per resolved package. Sorted by name for deterministic diffs and minimal merge conflicts.
| Field | Type | Notes |
|---|---|---|
name | string | Package name (e.g. react, @lpm.dev/owner.pkg) |
version | string | Exact resolved version |
source | string | absent | Source registry, e.g. registry+https://registry.npmjs.org. Absent for packages without a known source. |
integrity | string | absent | SRI integrity hash (sha512-…). Populated when the registry provides it. Always trusted on subsequent installs. |
dependencies | string[] | Direct deps as <local_name>@<version> entries. Skipped from output when empty. |
alias-dependencies | [string, string][] | npm-alias edges as [local_name, target_canonical_name] pairs. Only present when the package uses npm:<target>@<range> aliases. |
peers | string[] | Resolved peer dependencies as <peer_name>@<resolved_version> entries (same format as dependencies). Each entry is one of the package's declared peerDependencies intersected with the install set's resolved versions. Load-bearing for warm-install correctness — the v2 store's link-entry identity hashes peer pinning, so dropping these would let the warm install compute a different graph key than the cold install. Sorted by peer name; skipped from output when empty (the common case). |
tarball | string | absent | Tarball URL hint cached from resolve time. Speeds up the warm-install fast path by letting it skip the per-package metadata round-trip. Only valid for Source::Registry packages — pairing this hint with a non-Registry source is rejected at parse time. Absent on lockfiles produced before this hint shipped. |
dependencies format
dependencies = ["scheduler@0.25.0", "loose-envify@1.4.0"]<local_name>@<version> — the local-name is what the depending package writes in its own dependencies map. For non-aliased deps the local name equals the canonical registry name. For npm-alias deps (npm:react@^19.0.0 masquerading as react-canary), the local name diverges from the target — see alias-dependencies below.
alias-dependencies format
alias-dependencies = [["my-react", "react"]]Each [local_name, target_canonical_name] records that the package depends on my-react@<version> (in dependencies) but the actual target is react. Used to compute the right .lpm/<target>@<version>/ store path on link.
tarball field
tarball = "https://registry.npmjs.org/react/-/react-19.0.0.tgz"A dist-URL hint cache for Source::Registry packages. Lets the warm-install fast path skip the per-package metadata round-trip. For non-Registry sources (Source::Tarball, Source::Git), the URL is part of source identity (lives inside the source variant) — pairing them with this field is rejected at parse time.
[root-aliases]
[root-aliases]
my-alias = "actual-package"Maps root-level npm-alias edges so warm installs reproduce the original node_modules/<local>/ layout without re-resolving. Empty for projects without root-level aliases — and omitted entirely from output in that case (backwards-compatible with older lockfiles that pre-date alias support).
ambient-peer-installs
ambient-peer-installs = ["loose-envify", "scheduler"]Canonical names the resolver auto-installed at root scope to satisfy unmet peerDependencies (the eager peer-drain pass, on by default via autoInstallPeers = true). These packages are already in [[packages]] (they were resolved and extracted like any other dep) — this list carries the orthogonal signal "surface them at node_modules/<peer>/ even though they aren't in pkg.dependencies." Symmetric with [root-aliases] — both are project-side install-orchestration metadata, not per-package state.
Empty and omitted from output on the common no-auto-install path (project's dependencies block already covers every declared peer). See Resolver for the auto-install contract + toggle.
Determinism
The on-disk file is deterministic by construction:
[[packages]]entries are sorted by namedependenciesarrays inside each package are sorted- Optional fields are omitted when empty /
Nonerather than written as null
This makes git diff lpm.lock actionable: a new dep adds entries, a version bump rewrites a single package's fields, and you can spot supply-chain surprises without parsing.
Schema versioning
lockfile-version is schema-versioned, not tool-versioned. A version bump only happens when the on-disk shape changes. Older clients reading a lockfile with a higher lockfile-version should refuse with a clear error rather than silently misinterpreting fields.
See also
lpm.lockbformat — companion binary lockfile- Lockfile concept — design overview, when each file is read
lpm install --offline— installs entirely from the lockfilelpm install --strict-integrity— disallow trust-on-first-use for tarball-URL deps