How do you export an SBOM for a GitHub repository, and where does its content come from?
answer
- No build runs to produce it
- One standard document format, JSON serialisation
- It is the dependency graph, serialised
- Default branch, declared dependencies only
basics
~20 sGitHub exports an SBOM from the repository's dependency graph — via the Export SBOM action in the dependency graph view, or the dependency-graph SBOM REST endpoint. The output is SPDX JSON describing the default branch's known packages, not a build.
solid answer
~40 sGitHub can hand you a software bill of materials for a repository without you running anything: open the dependency graph view and use **Export SBOM**, or call the REST endpoint `GET /repos/{owner}/{repo}/dependency-graph/sbom` (easy with `gh api`). The response is SPDX JSON — packages with names, versions, licence information where GitHub knows it, and package-URL references. The key thing to say out loud is where the content comes from: the **dependency graph**, which GitHub builds by parsing manifest and lock files on the default branch. Nothing is built and nothing is scanned. So it inherits the graph's blind spots — vendored source, dependencies resolved only at build time, and anything not on the default branch. It is a fast, zero-effort inventory of declared dependencies, not a description of a particular artifact you shipped.
code
bash · 2 linesgh api /repos/my-org/my-service/dependency-graph/sbom \
--jq '.sbom.packages[] | "\(.name) \(.versionInfo)"'go deeper
Be able to say where the export lives — the dependency graph view or the dependency-graph SBOM endpoint — and that the document is SPDX JSON listing declared packages and versions.
Explain that content comes from parsing manifests and lock files on the default branch, so accuracy of transitive dependencies depends on whether a lock file exists.
Draw the line between a repository-level inventory and an artifact-level bill of materials, and say which question each one can actually answer.
Own what you attach to a customer or compliance response: an inventory of declared dependencies on the default branch, with its coverage gaps stated rather than implied.
## What GitHub gives you A repository on GitHub can produce an SBOM on demand in SPDX JSON. Two routes, same content: - **UI** — the repository's dependency graph view has an **Export SBOM** control that downloads the document. - **REST** — `GET /repos/{owner}/{repo}/dependency-graph/sbom`, which returns a JSON object with an `sbom` property holding the SPDX document. `gh api` makes this a one-liner and is what you use to sweep many repositories. SPDX is one of the two widely used SBOM document formats; GitHub's export uses it in JSON serialisation. ## What is inside The document names the repository as its subject and lists packages. Each package carries at least a name and a version (`versionInfo`), usually a package-URL external reference identifying it precisely in its ecosystem, and licence fields where GitHub has that information. That structure is what makes it machine-consumable — a downstream tool can match a package URL against an advisory's affected range without guessing at name formats. ## Where the content comes from — the part that matters GitHub does not build your project to produce this. The export is a rendering of the **dependency graph**, which GitHub derives by parsing supported manifest and lock files on the default branch: `package-lock.json`, `go.sum`, `Cargo.lock`, `pom.xml`, `requirements.txt` and their peers. Everything the graph knows, the SBOM contains; everything the graph misses, the SBOM misses too. That has practical consequences a junior candidate is expected to at least gesture at: - **It describes the default branch, not a release.** Export today and you get today's default branch, not the tree that produced last month's tagged artifact. - **It describes declared dependencies, not a built artifact.** Files baked into a container image by other means — a base image's system packages, something fetched by a build script — are not in it. - **Transitive accuracy depends on lock files.** Where a lock file pins the resolved set, the graph is precise. Where only a manifest with ranges exists, it is necessarily less so. - **It must be enabled.** The dependency graph is on by default for public repositories; on private ones it is a setting someone has to switch on, and until then the export has nothing to render. ## When this is the right tool The export shines for *inventory* questions: which of our repositories declare this library, and at what version. Because it is an API call, it scales across an organisation in a shell loop — no builds, no agents, no per-repository setup beyond having the graph enabled. It is the wrong tool when the question is about a specific shipped artifact — "what is inside the image running in production?" There the SBOM you want is generated during the build, from the build's own resolved dependency set, and attached to the artifact. GitHub's repository export cannot answer that, because it never saw the build. ## How it relates to the other GitHub surfaces The same dependency graph feeds vulnerability alerting on the repository and the dependency review of a pull request. So the SBOM export is best understood as "the graph, serialised for someone outside GitHub" — most often a customer's procurement or compliance team who wants a file rather than access to your repository. That is the request that most often triggers this in practice, and it is why the honest caveat matters: hand over a document, and be able to say precisely what it does and does not cover.
- Why might a customer's procurement team not be satisfied with this export?Because it describes the default branch's declared dependencies, not the artifact you shipped them. If they need to know what is inside a specific released binary or image — including anything the build pulled in and any base-image content — that SBOM has to be generated during the build and attached to the artifact.
- Does the export work on a private repository?Yes, but only once the dependency graph is enabled for it. The graph is on by default for public repositories and is a setting on private ones. With it off, there is nothing to serialise, which is the usual explanation for an unexpectedly empty or unavailable export.
saying these in an interview costs you the question
- Believing GitHub builds the project to produce the SBOM
- Assuming the export describes a released artifact
- Thinking it includes container base-image packages
- Expecting it on a private repo with the graph disabled
- Treating it as a vulnerability report