Lockfiles
Dagger automatically records the exact results of supported symbolic lookups in dagger.lock. Later runs reuse those recorded results, making container image and Git lookups reproducible.
Locking is enabled by default. Missing entries are resolved normally and written to the lockfile; existing entries are reused.
Lockfile format
New lockfiles use format version 2. Each non-empty file starts with a version header followed by one JSON tuple per lookup:
[["version","2"]]
["","container.from",["docker.io/library/alpine:latest","linux/amd64"],"sha256:..."]
Each entry contains, in order:
- namespace
- operation
- lookup inputs
- resolved value
Entries are ordered deterministically by namespace, operation, and inputs.
Version compatibility
Dagger reads both version 1 and version 2 lockfiles. Current API versions write version 2.
Version 1 entries include a fifth policy value, pin or float. Current API
versions preserve that behavior while reading them:
- A legacy
pinentry is reused. - A legacy
floatentry is resolved again when encountered.
Any subsequent write serializes the whole lockfile as version 2 and removes the
policy from every entry. Values that were not encountered remain unchanged and
become pinned; encountered float entries use their newly resolved values.
Version 2 does not store policies. Every recorded result is pinned until explicitly updated.
Clients using an API view from before pinned-by-default locking ignore the lockfile entirely. They neither read nor write it, even when run by a newer engine. This prevents an older module from silently acquiring new locking semantics.
Unknown future lockfile versions are rejected instead of being interpreted with potentially incompatible semantics.
Updating lockfiles
Use dagger update to refresh entries already recorded in dagger.lock:
dagger update
The update uses the current environment ambient authentication. Run it somewhere that can authenticate to any private registries or repositories referenced by the lockfile.
Ordinary commands discover and record missing entries automatically. There is no separate lock mode to select.
Lock-aware operations
These operations currently record and resolve lock entries:
| Operation | Inputs | Result |
|---|---|---|
container.from | [imageRef, platform] | image digest |
git.ref | [remoteURL, selector] | {"sha":"<commit>","ref":"<canonical-ref>"} |
All symbolic Git lookups use git.ref. The selector records the original
lookup intent: HEAD for git.head, a fully qualified
refs/heads/... or refs/tags/... selector for git.branch and
git.tag, and the caller's selector for git.ref.
The result always records the resolved commit SHA. It also records the
canonical ref when Git reports one. A migrated version 1 git.head pin can
omit ref because the old entry did not record the remote's default branch;
reading it does not contact the remote or guess a branch name.
git.commit is already pinned by its input and does not create a lock entry.