No. MODULE.bazel.lock records module resolution and extension results for reproducible builds, but it is not an SBOM and it just covers what the current build invocation used. Treat it as a useful input, then produce a real inventory from the build and compare.
What the lockfile holds
According to Bazel's documentation, the lockfile is generated under the workspace root and records module resolution and extension results. It holds hashes of remote registry files used in resolution, including not found entries, selected yanked versions when those are explicitly allowed, and per extension data such as digests and generated repository specs.
Two details matter for inventory work. First, it just includes dependencies included in the current invocation of the build. A target you did not build leaves no trace. Second, the data is aimed at reproducibility, so it has hashes and digests, not licenses, suppliers or package URLs.
Lockfile modes
The docs describe four values for the lockfile mode flag.
| Mode | Behavior |
|---|---|
| update (default) | Uses the file to skip known downloads, and adds missing information |
| refresh | Like update, and refreshes mutable data such as yanked versions |
| error | Fails if needed information is missing or outdated |
| off | Neither checked nor updated |
For an inventory job, error mode is a good guard: it tells you when the lockfile is stale instead of silently updating it. Remember that a build that passes may still be pruned later by update mode.
Why it is not enough
An SBOM wants component names, versions, relationships and ideally licenses. The lockfile is organized around resolution mechanics. Many things your product ships may come in through module extensions, which generate repositories from rules, and the lockfile stores their digests and specs, not a tidy component list.
A practical plan
- Commit the lockfile, as Bazel recommends, and pin the Bazel version with a version file, since the lockfile is specific to the Bazel version.
- Run the build in error lockfile mode in CI, so staleness fails loudly.
- Build every target that ships, not just a subset, so the invocation covers them.
- Produce the component list with a tool or script that understands your module graph and extensions.
- Add licenses and versions from each dependency's own metadata.
- Compare the list with the lockfile's registry entries to spot gaps.
Pitfalls
Merge conflicts in the lockfile are common. Bazel documents a git merge driver and a recovery routine. A bad merge can leave your inventory step reading a stale file.
Extensions that do not mark themselves reproducible may be left out of the lockfile. Those are exactly the ones worth reviewing by hand.
The hidden lockfile in the output base is an optimization with an unspecified format. Do not parse it.
A worked example
A team has a Bazel repository with two shipped binaries and a test suite. One engineer adds a new module dependency in MODULE.bazel and builds solely the test target on their laptop. The lockfile updates to include what that invocation used. This is a made up sequence.
Two weeks later CI builds the shipped binaries in lockfile error mode. The build fails because the lockfile is missing information needed by those targets. The engineer regenerates the lockfile by building the missing targets, commits it, and CI passes.
Here is what the story shows about SBOM work:
| Observation | Why it matters |
|---|---|
| The lockfile solely reflects the builds that ran | A partial build produces a partial record |
| Error mode surfaced the gap | Staleness became a visible failure |
| The fix was a commit, not a manual edit | The record stays machine maintained |
Using error mode as a gate
Error mode, as the docs describe, behaves like update mode but fails if needed information is missing or outdated, and it does not change the lockfile or make network requests during resolution. That makes it a reasonable pull request check: if the lockfile does not cover what the change needs, the check fails and asks for a commit. The docs add that reproducible extensions may still fetch, and that a file passing in this mode may still be pruned by update mode, so treat it as a helpful check, not a proof.
Merge conflicts
Lockfiles conflict. The docs mention a git merge driver that needs jq 1.5 or later, and say that simple conflicts in the registry file hash and yanked version sections can be resolved by keeping entries from both sides. For other conflicts, restore the lockfile from git, resolve MODULE.bazel and run the mod deps command. Put that routine in your contributor guide, because a wrong resolution leads to confusing failures later.
Pinning the tool version
The lockfile is specific to the Bazel version and can change even between backward compatible releases. The docs recommend a version manager and a version file. For SBOM purposes, record the Bazel version in your build metadata, since a different version may resolve differently.
From lockfile to inventory
The lockfile gives you registry hashes and extension data. To make an inventory you need names, versions, relationships and licenses. A reasonable approach is a script or tool that queries your module graph for the targets you ship, and then merges license data from each dependency. Compare its output with the lockfile's registry entries. Any module in the lockfile that is missing from the inventory, or the reverse, deserves a look.
Extensions deserve extra attention
Module extensions generate repositories. Some download archives from URLs. Those do not have a registry identity, so you should record them by URL and checksum. The docs note that extensions can opt out of the lockfile by returning metadata marking themselves reproducible, so review any extension in your graph that you did not write.
What to publish
For customers, publish the inventory for each shipped target, not the lockfile. The lockfile is an internal reproducibility artifact. Keep it in the repository and in your release archive for audits.
Where Safeguard fits
Safeguard can ingest and scan SBOMs, so once your pipeline writes one, you can check it with the free scan at gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen.
Step through the pull request check and look at what makes the gate pass or fail.
Quick check
Should I commit MODULE.bazel.lock?
Yes, the Bazel docs recommend it so everyone shares the same lockfile.
Does it list licenses?
No. It holds hashes, digests and generated specs for reproducibility.
Does a passing error mode build prove the lockfile is complete?
No. The docs note that a file that passes may still be pruned by update mode. Use it as a check, not a guarantee.
Sources
Last reviewed: 19 October 2026.