# lpm.lock format (/docs/reference/lockfile-format)



`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, SRI integrity hash, platform metadata, registry-signature evidence, and any cryptographically verified provenance evidence, so the next install can reproduce the same graph without trusting ambient registry state.

The companion [`lpm.lockb`](/docs/reference/lockb-format) binary lockfile is generated when the current binary wire format can represent the graph. `lpm.lock` is always authoritative; commit `lpm.lockb` when LPM CLI writes it.

## File location [#file-location]

`<project-root>/lpm.lock`

## Top-level shape [#top-level-shape]

```toml title="lpm.lock"
[metadata]
lockfile-version = 7
resolved-with = "greedy-fusion"
# Only present when the default linker auto-switched to isolated
# after detecting incompatible peer requirements.
auto-isolated-peer-conflicts = true

[importers.".".dependencies]
react = "^19.0.0"

[importers.".".dev-dependencies]
vite = "^6.0.0"

[patches."left-pad@1.3.0"]
path = "patches/left-pad@1.3.0.patch"
sha256 = "sha256-..."
original-integrity = "sha512-..."

[provenance."react@19.0.0#npm-..."]
subject-name = "pkg:npm/react@19.0.0"
subject-sha512 = "..."
integrated-time-secs = 1740000000
log-id = "..."
log-index = 123456
bundle-sha256 = "sha256-..."

[provenance."react@19.0.0#npm-...".snapshot]
present = true
publisher = "github:facebook/react"
workflowPath = ".github/workflows/publish.yml"
workflowRef = "refs/tags/v19.0.0"
attestation_cert_sha256 = "sha256-..."

[[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"
registry-published-at = "2025-01-01T00:00:00.000Z"
node-engine = ">=18"

[[packages.registry-signatures]]
keyid = "SHA256:..."
sig = "MEUCIQ..."

[[packages]]
name = "scheduler"
version = "0.25.0"
source = "registry+https://registry.npmjs.org"
integrity = "sha512-..."
os = ["darwin", "linux"]
cpu = ["arm64", "x64"]
libc = ["glibc"]
optional = true

# 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]` [#metadata]

| Field                          | Type   | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `lockfile-version`             | u32    | Schema version. Current: `7`. Schema-versioned (not tool-versioned) so older clients can refuse cleanly when the schema bumps. Version `2` made peer state authoritative; version `3` added platform + optional metadata; version `4` added registry signature metadata; version `5` added importer snapshots and patch checksum records; version `6` added per-package `engines.node`; version `7` added artifact-bound Sigstore provenance evidence. |
| `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.                                                                                                                                                    |

## `[importers]` [#importers]

```toml
[importers.".".dependencies]
react = "^19.0.0"

[importers.".".dev-dependencies]
vite = "^6.0.0"

[importers.".".lpm-overrides]
"left-pad" = "1.3.0"

[importers.".".catalogs.default]
react = "^19.0.0"

[importers."."]
patches-fingerprint = "sha256-..."
peer-dependency-rules-fingerprint = "sha256-..."
auto-install-peers = true
```

Importer snapshots record the manifest inputs that must match before a frozen install can replay the lockfile. LPM CLI currently writes the root importer as `"."`.

| Field                               | Type         | Notes                                                                          |
| ----------------------------------- | ------------ | ------------------------------------------------------------------------------ |
| `dependencies`                      | table        | `package.json > dependencies` exactly as declared.                             |
| `dev-dependencies`                  | table        | `package.json > devDependencies` exactly as declared.                          |
| `optional-dependencies`             | table        | `package.json > optionalDependencies` exactly as declared.                     |
| `peer-dependencies`                 | table        | `package.json > peerDependencies` exactly as declared.                         |
| `lpm-overrides`                     | table        | `package.json > lpm.overrides` after catalog references are resolved.          |
| `overrides`                         | table        | npm-style `package.json > overrides` after catalog references are resolved.    |
| `resolutions`                       | table        | yarn-style `package.json > resolutions` after catalog references are resolved. |
| `catalogs`                          | nested table | Catalog ranges visible to this importer.                                       |
| `patches-fingerprint`               | string       | Hash of `lpm.patchedDependencies`; absent when no patches are declared.        |
| `peer-dependency-rules-fingerprint` | string       | Hash of `lpm.peerDependencyRules`; absent when default/empty.                  |
| `auto-install-peers`                | bool         | Effective `autoInstallPeers` value captured for frozen replay.                 |

## `[patches]` [#patches]

```toml
[patches."left-pad@1.3.0"]
path = "patches/left-pad@1.3.0.patch"
sha256 = "sha256-..."
original-integrity = "sha512-..."
```

Patch records bind `package.json > lpm.patchedDependencies` to the exact patch file bytes LPM CLI is allowed to replay. The table key is the exact patched package selector (`<name>@<version>`).

| Field                | Type   | Notes                                                                                                                             |
| -------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `path`               | string | Patch file path relative to the project root.                                                                                     |
| `sha256`             | string | SHA-256 digest of the patch file contents. Install hard-errors if the current file hash differs from this value.                  |
| `original-integrity` | string | SRI integrity of the pristine package bytes the patch was authored against. Install also verifies this before applying the patch. |

`[patches]` is TOML-only metadata. Projects with patch records skip `lpm.lockb` and remove any stale binary companion.

## `[[packages]]` [#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.                                                                                                                                                                                                                                                                                                                                                                                              |
| `registry-signatures`   | table\[]             | npm-compatible `dist.signatures` entries persisted as nested `[[packages.registry-signatures]]` tables. Skipped when absent.                                                                                                                                                                                                                                                                                                                                                                                  |
| `registry-published-at` | string \| absent     | Publish timestamp used to verify npm registry signing-key expiry without rehydrating package metadata.                                                                                                                                                                                                                                                                                                                                                                                                        |
| `os`                    | string\[]            | `package.json > os` restrictions for this version. Skipped when empty.                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `cpu`                   | string\[]            | `package.json > cpu` restrictions for this version. Skipped when empty.                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `libc`                  | string\[]            | `package.json > libc` restrictions for this version. Skipped when empty.                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `node-engine`           | string \| absent     | The package's `package.json > engines.node` constraint. Warm and frozen installs revalidate it against the effective Node.js version and `engine-strict` setting.                                                                                                                                                                                                                                                                                                                                             |
| `optional`              | bool                 | Present as `true` when the package is reachable only through optional dependency edges. Used with platform filtering so warm installs can skip incompatible optional packages and fail incompatible required packages.                                                                                                                                                                                                                                                                                        |
| `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-format]

```toml
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-format]

```toml
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-field]

```toml
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.

### Platform fields [#platform-fields]

```toml
os = ["darwin", "linux"]
cpu = ["arm64", "x64"]
libc = ["glibc"]
optional = true
```

LPM CLI records `os`, `cpu`, and `libc` restrictions from the package version's manifest. Empty arrays are omitted. Warm installs replay the same host filtering as fresh installs: incompatible optional packages are skipped; incompatible required packages fail loudly.

The `optional = true` bit means this package is only reachable through optional dependency edges. It is what lets the lockfile fast path distinguish "safe to skip on this host" from "required package cannot run here."

### Registry signatures [#registry-signatures]

```toml
registry-published-at = "2025-01-01T00:00:00.000Z"

[[packages.registry-signatures]]
keyid = "SHA256:..."
sig = "MEUCIQ..."
```

When npm metadata includes `dist.signatures`, LPM CLI persists the signature payloads and the version publish timestamp. Install-time signature verification can then run from the lockfile fast path without fetching the full package metadata again. The verifier still checks the package integrity hash and registry signing keys; the lockfile stores evidence, not a cached pass/fail verdict.

## `[provenance]` [#provenance]

```toml
[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.

## `[root-aliases]` [#root-aliases]

```toml
[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]

```toml
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]]&#x60; (they were resolved and extracted like any other dep) — this list carries the orthogonal signal &#x2A;"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](/docs/packages/resolver#peerdependencies-and-optionaldependencies) for the auto-install contract + toggle.

## Determinism [#determinism]

The on-disk file is deterministic by construction:

* `[[packages]]` entries are sorted by name
* `dependencies` arrays inside each package are sorted
* `[provenance]` entries are sorted by their full package/source key
* Optional fields are omitted when empty / `None` rather 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 [#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 [#see-also]

* [`lpm.lockb` format](/docs/reference/lockb-format) — companion binary lockfile
* [Lockfile concept](/docs/packages/lockfile) — design overview, when each file is read
* [`lpm install --offline`](/docs/packages/install) — installs entirely from the lockfile
* [`lpm install --strict-integrity`](/docs/packages/install) — disallow trust-on-first-use for tarball-URL deps
