Skip to main content
info

Documentation is currently for moon v2 and latest proto. Documentation for moon v1 has been frozen and can be found here.

Lockfiles

v0.51.0

Lockfiles allow you to lock the exact version (and checksum) of every tool installed in a project, ensuring that all machines — your own, your teammates', and CI — resolve and install identical tools, regardless of when they run. If you've used package managers like npm, Cargo, or uv, the concept is the same, just applied to the tools themselves.

caution

Lockfiles are currently unstable. The functionality works as documented, but behavior and the lockfile structure may change between releases. If you run into any issues, please report them!

Enabling lockfiles

Lockfiles are opt-in, and can be enabled with the settings.unstable-lockfile setting in a .prototools file.

.prototools
node = "22"

[settings]
unstable-lockfile = true

Once enabled, a .protolock file will be created in the same directory as the .prototools file, the next time records are written (typically by proto install). This file should be committed to your version control system, so that other machines can make use of it.

If the setting is later disabled or removed, the sibling .protolock file will automatically be deleted the next time proto runs.

How it works

Scopev0.60.0

A lockfile is scoped to the .prototools configuration file in which the setting was enabled.

  • The lockfile only tracks tools with versions defined in its sibling .prototools file. Tools installed ad-hoc (without a configured version) are tracked by the closest configuration file.
  • Versions defined in nested configuration files are not included in a parent's lockfile. To lock a nested configuration, enable the setting in that file as well.
  • Multiple lockfiles can exist within a directory tree (for example, one per project in a monorepo), with each operating independently.

Before v0.60, a lockfile locked its directory and all of its subdirectories, similar to how package manager workspaces function, and defining nested lockfiles would trigger an error.

Records

For each tool, the lockfile stores a list of records, with each record representing an installation for a specific version requirement, operating system, and architecture. Records are grouped by the tool identifier using TOML's array of tables syntax.

.protolock
# Generated by proto. Do not modify!

[[tools.node]]
os = "linux"
arch = "x64"
spec = "22"
version = "22.17.0"
checksum = "sha256:325c377fbb4e547444a5da404e474fda52eb0adb3bbafcd25eee38e5766a1cfa"

[[tools.node]]
os = "macos"
arch = "arm64"
spec = "22"
version = "22.17.0"
checksum = "sha256:29b8fc16b1d1b0b7d19d444b8fac9e6ca4b39ee01bd097756975f92a25deba71"

Each record supports the following fields:

  • spec - The version requirement that was requested, typically from a .prototools file.
  • version - The exact version that the requirement resolved to.
  • checksum - A checksum of the installed artifact, prefixed with its algorithm. Builds from source and native installations may not have a checksum.
  • os / arch - The operating system and architecture the record applies to. Since pre-built artifacts differ per platform, a record exists for each combination.
  • backend - The backend the tool was installed with, if applicable.

Records are created and updated when a tool is explicitly installed with proto install, and removed when uninstalled with proto uninstall. Do not edit this file manually — proto owns it entirely.

Version resolution

When a version requirement is being resolved — during an install, or when detecting versions for proto run and shims — proto will first look for a matching record in the applicable lockfile. A record matches when it has the same requirement (spec), backend, operating system, and architecture. If a match is found, the exact version from the record is used, instead of re-resolving the requirement against the tool's available versions.

This is what guarantees determinism: a requirement like node = "22" will keep resolving to the locked 22.17.0, even after newer 22.x versions have been released. To break out of this and re-resolve, pass --update-lockfile to proto install, which will skip the lockfile during resolution, and update the record with the newly resolved version.

$ proto install node --update-lockfile

Checksum verification

When installing a version that has a lockfile record, proto will verify the installation against that record: the checksum of the artifact must match the locked checksum, and the operating system and architecture must line up. If they don't, the install fails with an error — ensuring that the artifact installed on another machine (or in CI) is the same one that was originally locked.

When a record is migrated to a new version (through the commands below), its checksum is removed, and will be re-populated on the next install.

Lockfile-aware commandsv0.60.0

Beyond installation, lockfiles are integrated across the command line.

  • proto outdated and proto status display a "Locked" column, showing the version locked for each configured requirement, and include a locked_version field in their --json output.
  • proto outdated --update updates matching records when writing new versions to their respective configuration files.
  • proto pin (and proto install --pin) migrates matching records to the newly pinned requirement, while proto unpin removes them entirely.
  • proto versions labels versions that have a record with "locked", and includes a locked field in its --json output.
  • proto debug config renders .protolock files alongside their sibling configuration files.
  • proto clean does not remove records when cleaning stale versions, as the version may still be required by a configuration, or in use on other machines.
  • proto diagnose audits the health of lockfiles, reporting warnings for records that are missing a resolved version, duplicate records for the same requirement, and stale records that no longer match a configured version.