Safeguard
Developer Tools•

Gradle SBOM: should you run the aggregate or the direct task?

Gradle builds can make one aggregate SBOM or one per project. Here is when each fits, the commands to run, and a failure mode to know about.

Safeguard Security Team
4 min read

Run the aggregate task when you need one SBOM for the whole Gradle build, and the direct task when each project ships on its own. In the CycloneDX Gradle plugin 3.x these are cyclonedxBom and cyclonedxDirectBom. The aggregate is the recommended starting point.

The two tasks in plain terms

A direct SBOM describes one Gradle project and its dependencies. An aggregate SBOM is composed from the direct SBOMs of the projects that contribute to it. That composition is why running the aggregate task also generates the direct files it consumes.

TaskUse it whenDefault output
cyclonedxBomYou need one SBOM for the buildbuild/reports/cyclonedx/bom with json and xml
cyclonedxDirectBomYou need an SBOM per project, or for one projecteach project's build/reports/cyclonedx-direct/bom

Where you apply the plugin decides the scope

In plugin 3.x, applying the plugin to a project registers the direct task on that project and its subprojects. It registers the aggregate task only on the project where you applied it. Apply it on the root project and the aggregate covers the root plus every contributing subproject. Apply it on a single subproject and the aggregate covers that subtree.

This is the usual source of confusion. A team applies the plugin in a leaf module, runs the aggregate task, and wonders why other modules are missing.

A decision guide

Ask what the SBOM is attached to.

  1. One deployable built from the whole repository, such as a single service with several internal modules: use the aggregate.
  2. Several independently shipped artifacts in one repository, such as a library and a command line tool: use the direct task per project, and attach each file to the artifact it describes.
  3. A mix: generate both, and label them so nobody confuses a repository-wide file with a per-artifact one.

The README makes a related point about matching an SBOM to what it describes: an artifact should be paired with an SBOM whose boundary covers it. A jar from one project normally pairs with that project's direct SBOM. Use the aggregate only when the distribution really represents the same set of projects.

The commands

Aggregate for the whole build:

./gradlew cyclonedxBom

All direct SBOMs without the aggregate:

./gradlew cyclonedxDirectBom

One subproject:

./gradlew :subproject:cyclonedxDirectBom

A failure mode worth knowing

The aggregate is built from direct SBOMs of projects whose direct tasks are enabled. If an expected direct SBOM is missing, aggregation fails instead of producing an incomplete document. That is a good default, because a quietly partial SBOM is the worse outcome.

To keep a project out of the aggregate, disable its direct task with enabled set to false in that project's build script. The README warns against using an execution time condition such as onlyIf for this. A task skipped only at execution time is still an expected producer, so the aggregate fails when its output is missing.

Try it yourself

Click through it at your own pace, or open it full screen. Notice how one inventory can be viewed per project or rolled up, which is the same choice you make with these two tasks.

Safeguard builds an SBOM and dependency inventory from your repositories, and the free scan is a way to see a Gradle project's dependencies without changing your build.

Quick check

Does the aggregate task also create per-project files?

Yes. It generates the direct SBOMs it consumes, so you get both with the default configuration.

Why is a module missing from my aggregate?

Most likely the plugin was applied below the root project, or that module's direct task is disabled. Check where the plugin is applied first.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.