Safeguard
Software Supply Chain•

How do you generate an SBOM for a Dart and Flutter project?

Build the SBOM from pubspec.lock for the exact Dart versions, then add the native iOS and Android dependencies a Flutter app also ships. Verify the output.

Safeguard Security Team
5 min read

To generate an SBOM for a Dart or Flutter project, resolve dependencies so pubspec.lock is current, convert its exact package versions into a CycloneDX or SPDX document, then add the native iOS and Android dependencies that a Flutter app also ships. Check the result against what the built app contains.

What does pubspec.lock give you?

The Dart documentation says pubspec.lock records the exact versions of all dependencies, both direct and transitive, and compares it to Ruby's Gemfile.lock. That is the right starting point for an SBOM, because an SBOM needs resolved versions, not the version ranges in pubspec.yaml.

There is one rule that matters for SBOM work. The docs say to commit the lock file for application packages and not for regular library packages. A Flutter app is an application, so the committed lock file reflects what you build. A published Dart library has no committed lock file, so an SBOM for it should be generated from a fresh resolution in CI and labelled with the date and the Dart SDK version.

The pubspec.yaml file also has dev_dependencies, described in the docs as needed only during development of the package itself, and a dependency_overrides section for temporary overrides. Decide whether dev dependencies belong in your SBOM. Most teams ship two views: runtime components for customers, and a full list for internal vulnerability review. If dependency_overrides is in use, record it, because it means you are not running what the ranges say.

What format should you produce?

Both CycloneDX and SPDX are widely accepted. OWASP recognises the CycloneDX BOM predicate type for CycloneDX bills of materials, including SBOM. Pick the one your customers or regulators request, and keep one component entry per package: name, exact version, and a package URL (purl) written in the format the package-url specification defines for the ecosystem. I could not retrieve that specification page when preparing this post, so check the exact purl form against it, or against your tool's output.

A constructed minimal approach: run dart pub get so the lock file is fresh, parse the YAML under packages, and emit a component for each entry. A short script is enough to prove the idea:

import yaml, json

lock = yaml.safe_load(open("pubspec.lock"))
components = [
    {"type": "library", "name": name, "version": entry["version"]}
    for name, entry in lock["packages"].items()
]
bom = {"bomFormat": "CycloneDX", "specVersion": "1.5", "components": components}
json.dump(bom, open("sbom.json", "w"), indent=2)

For production use, prefer a maintained SBOM generator that supports Dart, and check its documentation for current support, since I could not confirm a specific tool in the CycloneDX tool listing I was able to read.

What does the lock file miss in a Flutter app?

A Flutter app is not only Dart. The iOS build pulls native libraries through its own dependency manager and the Android build uses Gradle. Plugins you add through pub often bring native code with them. The SBOM from pubspec.lock lists the Dart packages, not the native libraries those plugins link, nor the Flutter engine and framework themselves. Generate separate inventories from the iOS and Android lock files, then merge them, or use a scanner that reads all of them.

Also record the Flutter and Dart SDK versions, since they are part of what you ship.

How do you check the SBOM is right?

Compare counts and spot-check. Pick five packages from the SBOM and confirm each appears in the built app's dependency list. Pick five from the app's plugin list and confirm each appears in the SBOM, including native ones. Regenerate in CI on each release, store the file with the build artifact, and diff it against the previous release so changes are reviewed.

See the full walkthrough at /demos/sca-dependency-inventory.

What to do

  1. Commit pubspec.lock for apps, and generate libraries' SBOMs from a fresh resolve in CI.
  2. Convert the lock file to CycloneDX or SPDX, with exact versions and package URLs.
  3. Decide what to do with dev dependencies and any overrides, and say so in the file.
  4. Add native iOS and Android inventories, plus SDK versions.
  5. Spot-check against the built app, then regenerate on every release.
  6. Scan the SBOM for known vulnerabilities. Safeguard's free scan at gold.safeguard.sh/scan checks up to 100 dependencies in the browser.

Quick check

Should I commit pubspec.lock?

For applications, yes. For regular library packages, the Dart docs say no, so generate their SBOM from a fresh resolution.

Does pubspec.lock cover everything a Flutter app ships?

No. It covers Dart packages. Native iOS and Android libraries and the SDKs need their own inventories.

Sources

Last reviewed: 18 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.