To generate an SBOM for a Go project, use a tool that reads go.mod and the build, such as the open source cyclonedx-gomod. Choose between an application view of what is compiled in, a module view of everything required, or a binary view, and write the result in CycloneDX format.
Why does Go need a choice of view?
A Go module can contain many packages, and a build includes only some. The cyclonedx-gomod documentation describes three subcommands that answer different questions.
- The app subcommand includes only modules the target application actually depends on. It leaves out modules needed only by tests or by packages the application does not import, and it evaluates build constraints, which gives a detailed view of what is compiled into the binary.
- The mod subcommand includes the aggregate of modules required by all packages in the module, optionally including tests. It does not evaluate build constraints, so it is the whole picture.
- The bin subcommand produces rudimentary SBOMs from binaries built with Go module support.
For a customer asking what is in the thing you shipped, app or bin is the honest answer. For a security team triaging a new advisory against a repository, mod is the safe superset.
Which should you use when?
Use app for a deliverable service or CLI. Use bin when you only have the artifact, for example a vendor binary you must inventory, remembering the result is rudimentary. Use mod for libraries, where no single application exists.
A constructed example: a service has a build tag that includes a debug exporter pulling an extra module. The app SBOM for the production build excludes it. The mod SBOM includes it. If an advisory lands on that module, the mod view tells you to look, and the app view tells you whether production is affected.
What else belongs in the SBOM?
Record the Go toolchain version, since the standard library is part of what ships and has its own advisories. Record the build flags and the commit hash. Keep go.sum committed so the dependency hashes can be checked later.
How do you use the SBOM once you have it?
An SBOM sitting in a folder helps nobody. Feed it to a vulnerability scan on every release, and keep the previous version for comparison. When a new advisory appears, search the stored SBOMs for the affected module and version to learn which releases contain it. That is the moment the file earns its keep: the question changes from "do we use this module" to "which of our releases shipped it, and to whom."
How to check or apply this
- Install the generator and run the app subcommand against your main package, writing CycloneDX output.
- Run the mod subcommand for the whole module and compare the two component lists.
- Store both files with the release, named with the version and commit.
- Add the generation step to CI so every release has a fresh SBOM, not one from last quarter.
- Scan the SBOM against vulnerability data, and check which findings are in the app view.
- Validate the file against the CycloneDX schema before you send it to anyone.
- Regenerate whenever dependencies change.
Safeguard ingests SBOMs and scans project dependencies, and its reachability analysis helps separate a vulnerable module that is present from one your code calls.
Quick check
Why do app and mod SBOMs differ?
App includes only modules the application depends on and evaluates build constraints. Mod includes everything required by all packages in the module and does not evaluate constraints.
Can I make an SBOM from a binary alone?
Yes, for binaries built with Go module support, but the cyclonedx-gomod documentation calls the result rudimentary.
Sources
Last reviewed: 18 October 2026.