lpm.lock format
Read the TOML lockfile fields, exact dependency targets, workspace records, and validation rules.
lpm.lock records the exact dependency graph for a project or workspace. LPM CLI uses this file for repeatable installs.
The current schema is 13. It uses TOML only. Commit lpm.lock with the manifest changes that produced it.
lpm install
git diff -- lpm.lock
lpm install --frozen-lockfileUse Lockfiles for everyday workflows. This page describes the file fields and their relationships.
Location and authority
| Project | Location |
|---|---|
| Standalone package | <project-root>/lpm.lock |
| Workspace | <workspace-root>/lpm.lock |
A workspace lockfile contains an importer for the root and each retained member. An importer records that project's manifest inputs and selected packages.
Member commands read their importer from the root file. A successful recursive migration removes obsolete member lockfiles.
LPM CLI reads authoritative TOML for installs. It does not fall back to a binary companion if TOML is missing or invalid. The file limit is 64 MiB, for both reads and writes.
File structure
The following excerpts illustrate field placement. Placeholder hashes and omitted rows make them unsuitable as complete lockfiles. Let lpm install generate the file.
# Root-level arrays go before any table header.
ambient-peer-installs = ["react"]
[metadata]
lockfile-version = 13
resolved-with = "greedy-fusion"
[importers."."]
auto-install-peers = true
[importers.".".dependencies]
widget = "^1.0.0"
[[packages]]
instance-id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
name = "widget"
version = "1.0.0"
source = "registry+https://registry.npmjs.org"
integrity = "sha512-..."
dependencies = ["helper@2.0.0"]
[packages.dependency-targets]
helper = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
[root-resolutions.widget]
instance-id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
package = "widget"
version = "1.0.0"
source = "registry+https://registry.npmjs.org"| Top-level field | Purpose |
|---|---|
metadata | Schema version, resolver name, and automatic linker selection. |
importers | Manifest snapshots and workspace package selections. |
packages | Package rows for a standalone graph. |
workspace-packages | Shared package rows for a workspace graph. |
root-resolutions | Exact packages linked at the project root. |
root-aliases | Root dependency names that differ from canonical package names. |
ambient-peer-installs | Automatically installed peers exposed at the project root. |
patches | Patch paths, patch hashes, and original package integrity. |
catalogs | Resolved catalog entries. |
provenance | Previously verified publication evidence. |
[metadata]
| Field | Type | Meaning |
|---|---|---|
lockfile-version | Integer | File schema version. Current: 13. |
resolved-with | String, optional | Resolver name, such as greedy-fusion or pubgrub. |
auto-isolated-peer-conflicts | Boolean | true when peer conflicts caused automatic isolated linking. Omitted when false. |
The automatic linker record preserves the layout on later installs. An explicit linker configuration takes precedence.
[importers]
A standalone project uses importers.".". A workspace also uses member paths, such as importers."packages/web".
Importer paths must stay within the lockfile root.
Frozen installs compare these manifest inputs before they reuse the graph:
| Field | Type | Meaning |
|---|---|---|
dependencies | Table | Declared production dependencies. |
dev-dependencies | Table | Declared development dependencies. |
optional-dependencies | Table | Declared optional dependencies. |
peer-dependencies | Table | Declared peer dependencies. |
lpm-overrides | Table | Project lpm.overrides, with catalog references resolved. |
overrides | Table | npm overrides, with catalog references resolved. |
resolutions | Table | Yarn resolutions, with catalog references resolved. |
catalogs | Nested table | Catalog ranges visible to the importer. |
patches-fingerprint | String, optional | Fingerprint of the project's patch declarations. |
peer-dependency-rules-fingerprint | String, optional | Fingerprint of nondefault peer rules. |
auto-install-peers | Boolean, optional | Effective automatic peer-install setting. |
workspace-root-peer-providers-fingerprint | String, optional | Fingerprint of the root packages that provide workspace peers. |
Workspace importers also carry their own graph records:
| Field | Type | Meaning |
|---|---|---|
locked-packages | String array | Package IDs selected from workspace-packages. |
root-resolutions | Table | Exact root selections for this importer. |
root-aliases | Table | Root aliases for this importer. |
ambient-peer-installs | String array | Automatic peers exposed in this importer's root. |
patches | Table | This importer's patch evidence. |
catalog_resolutions | Nested table | Resolved catalog entries. This field uses an underscore. |
provenance | Table | This importer's verified publication evidence. |
auto-isolated-peer-conflicts | Boolean | Automatic isolated linking for this importer. |
Package rows
Standalone files use [[packages]]. Workspace files use the same fields under [workspace-packages."sha256:<digest>"].
| Field | Type | Meaning |
|---|---|---|
instance-id | String | Required 64-character lowercase hexadecimal ID for this exact graph instance. |
name | String | Canonical package name. |
version | String | Exact package version. |
source | String, optional | Registry, tarball, Git, directory, or link source identity. |
integrity | String, optional | Package archive SRI hash. Required for remote tarball and GitHub rows. |
unpacked-size | Positive integer, optional | Registry-reported unpacked bytes. Used as a download scheduling hint. |
manifest-fingerprint | String, optional | Semantic manifest hash for mutable directory and link sources. |
dependencies | String array | Dependency-local names and selected versions or source IDs. |
dependency-targets | Table | Exact target instance for each dependency-local name. |
alias-dependencies | Array of string pairs | Local dependency name and canonical target name. |
peer-edges | Table array | Resolved peer identities. |
peer-targets | Table | Exact target instance for each peer-local name. |
os | String array | Operating-system restrictions. |
cpu | String array | CPU restrictions. |
libc | String array | C library restrictions. |
optional | Boolean | true when only optional paths reach the package. |
node-engine | String, optional | The package's engines.node requirement. |
tarball | String, optional | Cached archive URL for a registry package. |
registry-signatures | Table array | Registry signatures, with keyid and sig fields. |
registry-published-at | String, optional | Publication timestamp used for registry signing-key checks. |
Empty collections and most absent optional fields are omitted. Legacy files can contain peers; current writers use peer-edges and peer-targets.
Sources and integrity
Common source forms include:
registry+https://registry.npmjs.org
tarball+https://example.com/package.tgz
git+https://github.com/owner/repo.git#<40-character-commit>
directory+<path>
link+<path>The importer keeps the declared range or Git reference. The package row records the selected version and immutable remote source. Root replay checks both source kind and source identity. A registry declaration cannot select a Git row with matching name and version.
Directory and link rows require manifest-fingerprint = "sha256-<64-character-digest>". They cannot carry archive integrity.
LPM CLI checks the local manifest's name, version, and semantic fingerprint before reuse.
Registry packages normally carry an integrity hash. --strict-integrity rejects a registry package without one; otherwise first retrieval can establish the hash.
See lpm install for integrity policy.
The tarball field is a URL hint for registry packages. A non-registry source with this field is invalid.
URL hints remain subject to download safety checks; they do not replace source identity or integrity checks.
Dependency and peer targets
dependencies = ["my-react@19.0.0"]
alias-dependencies = [["my-react", "react"]]
[packages.dependency-targets]
my-react = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[[packages.peer-edges]]
local-name = "react"
target-name = "react"
target-version = "19.0.0"
# Optional source identity:
# target-wrapper-id = "<source-id>"
[packages.peer-targets]
react = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"A dependency entry uses <local-name>@<version>. For local, tarball, or Git targets, the suffix can be a canonical source ID.
The matching exact target selects the package instance.
Dependency-target keys must match dependency-local names. Peer-target keys must match peer-local names. Each target must exist in the same standalone graph or importer selection.
Packages can share a name, version, and archive but need different instances because their dependency or peer targets differ. Missing, ambiguous, or inconsistent targets fail validation.
Platform and engine checks
LPM CLI applies os, cpu, and libc restrictions again when it reuses the lockfile.
It skips incompatible optional packages. Incompatible required packages fail the install.
Dependency Node.js requirements are checked against the effective runtime and engine-strict setting.
See npm compatibility.
[root-resolutions] and aliases
Each root selection contains these fields:
| Field | Meaning |
|---|---|
instance-id | Exact selected graph instance. Required in schema 13. |
package | Canonical package name. |
version | Exact selected version. |
source | Source identity, when present. |
The table key is the name exposed in node_modules. The entry must agree with its target row.
The same shape applies to importers.<path>.root-resolutions.
root-aliases maps local names to canonical names. For example:
[root-aliases]
my-react = "react"ambient-peer-installs lists automatic peers exposed at the root even when the manifest does not declare them as direct dependencies.
The corresponding package rows and exact root selections remain necessary.
[workspace-packages]
Workspace files share package rows across importers. Each row key is sha256:<digest> and binds the row contents, including exact edge targets.
[importers."packages/web"]
locked-packages = ["sha256:<row-digest>"]
[workspace-packages."sha256:<row-digest>"]
instance-id = "<64-character-instance-id>"
name = "react"
version = "19.0.0"
source = "registry+https://registry.npmjs.org"
integrity = "sha512-..."Each importer must select every package needed by its graph. Commands for one member see only that selection.
Validation rejects unsafe importer paths, duplicate selections, missing rows, unreferenced rows, incorrect content addresses, and inconsistent exact targets.
[patches]
[patches."left-pad@1.3.0"]
path = "patches/left-pad@1.3.0.patch"
sha256 = "sha256-<patch-digest>"
original-integrity = "sha512-..."The key identifies the exact package version. path is relative to the project root.
sha256 binds the patch bytes; original-integrity binds the original package archive.
An install fails if either binding does not match. See lpm patch.
[catalogs]
[catalogs.default.react]
specifier = "^19.0.0"
version = "19.0.0"
reference = "catalog:"Each resolved entry records its requested specifier, exact version, and original catalog reference (such as catalog:).
Workspace importers store this shape under catalog_resolutions. Their catalogs field instead records declared catalog ranges.
See lpm catalog.
[provenance]
[provenance."axios@1.14.0#npm-036b43b16792c643"]
subject-name = "pkg:npm/axios@1.14.0"
subject-sha512 = "dd8f32ae..."
integrated-time-secs = 1774638099
log-id = "wNI9atQG..."
log-index = 1189268120
bundle-sha256 = "sha256-75564031..."
[provenance."axios@1.14.0#npm-036b43b16792c643".snapshot]
present = true
publisher = "github:axios/axios"
workflowPath = ".github/workflows/publish.yml"
workflowRef = "refs/tags/v1.14.0"
attestation_cert_sha256 = "sha256-9a9a6a..."The table key is <name>@<version>#<source-id>, so evidence is attached to one exact package version from one exact source. Only successfully verified evidence is written.
| Field | Type | Notes |
|---|---|---|
subject-name | string | Exact npm package URL signed by the attestation, pkg:npm/<name>@<version>. |
subject-sha512 | string | Lowercase hexadecimal SHA-512 digest of the signed tarball subject. It must match the package entry's SHA-512 SRI integrity. |
integrated-time-secs | u64 | Rekor integrated timestamp from the verified transparency-log entry. |
log-id | string | Identity of the transparency log that recorded the attestation. |
log-index | i64 | Verified transparency-log index. |
bundle-sha256 | string | SHA-256 digest of the original Sigstore bundle bytes. |
snapshot.present | bool | Must be true; absent or unverified provenance is never locked as evidence. |
snapshot.publisher | string | absent | Publisher identity extracted from the verified certificate, such as github:axios/axios. |
snapshot.workflowPath | string | absent | Trusted publishing workflow path. |
snapshot.workflowRef | string | absent | Git ref used for this publication. |
snapshot.attestation_cert_sha256 | string | absent | SHA-256 digest of the verified leaf certificate. |
The reader rejects orphaned evidence, empty required fields, malformed digests, non-npm subjects, subject name/version mismatches, source mismatches, and subject digests that do not match the locked package integrity. A frozen install can therefore replay internally consistent evidence without fetching the attestation again.
lpm.lock is trusted project input. It stores derived evidence, not the original Sigstore bundle, so frozen replay does not rerun the certificate-chain, transparency-log, or signed-statement verification and cannot independently detect a sophisticated edit that changes all related derived fields consistently. Protect and review lockfile changes like source code. Online attestation-cache hits do rerun verification because that cache stores the original bundle bytes.
Ordering and review
Package rows sort by name, version, source identity, and instance ID. Workspace row tables sort by content address.
Importer locked-packages entries follow package identity order, rather than digest order.
Dependency arrays and evidence tables also have deterministic ordering.
A dependency update can change several package rows, exact targets, root selections, and workspace content addresses. Review source changes, integrity changes, new dependencies, and publication evidence before you commit the file.
Schema upgrades and recovery
lockfile-version identifies the file schema, rather than the CLI release. Older clients reject unsupported newer schemas.
Frozen and offline installs require the current exact-instance graph.
For an older file, run an online install before CI or offline use:
lpm install --no-frozen-lockfileFor a workspace, refresh every retained importer from the root:
lpm install --recursive --no-frozen-lockfileReview and commit the result. If a merge produces an invalid file, restore a valid revision before you regenerate it. Do not repair hashes or exact targets by hand. lpm doctor reports lockfile problems.
Legacy binary files
Older workflows can leave lpm.lockb. Migration without installation can also produce a version 12 staging file and a binary companion.
The subsequent online install creates the current TOML graph.
LPM CLI retains binary validation and repair support for those files. Current schema 13 cannot use the binary format. A successful non-frozen install removes an obsolete companion, including when the TOML graph is unchanged. Frozen installs preserve existing lockfile bytes. Commit the companion removal with any TOML update. See lpm migrate for staging and rollback behavior.