Scan every module that has its own go.mod, and do not rely on go.work alone. The Go reference says a use directive adds one module directory and does not add modules in subdirectories. Also note that workspace mode can select different versions from the ones a single module build would use.
What go.work does
The Go modules reference describes go.work as a file that adds modules on disk to the set of main modules in a workspace. Each use directive names a relative path to a directory containing a go.mod. A use directive does not add modules that live in subdirectories of its argument, so nested modules need their own entries.
The go command maintains a go.work.sum file for hashes used by the workspace that are not in the modules' go.sum files.
go 1.23.0
use ./services/api
use ./services/worker
use ./libs/shared
Finding every module
Do not assume the use list is complete. List the go.mod files directly:
git ls-files '*go.mod'
Compare that to the use entries. A module with no entry is not part of the workspace build. It may still ship on its own.
| Situation | What it means for scanning |
|---|---|
| go.mod listed in go.work | Part of workspace builds |
| go.mod not listed | Built separately, scan it on its own |
| Nested module under a used folder | Needs its own use entry |
Versions can differ between modes
In workspace mode, all workspace modules are main modules, and minimal version selection runs over a graph built from all of them. The highest required version of each dependency across the workspace wins. So a vulnerable version required by one module can be raised by another module's requirement, and the reverse is also possible.
Replace directives in go.work override replace directives in module files. A wildcard replace in go.work overrides a version specific replace in a go.mod file.
The effect is that what you test locally in workspace mode might differ from what each module ships when built alone. Scan each module in its own single module context, using the environment variable that turns workspace mode off, because that matches how an individual service is usually built in CI.
GOWORK=off go list -m all
Should you commit go.work?
The Go reference advises against committing go.work in most cases, noting that a checked in file may cause CI to select and test the wrong versions of a module's dependencies. It names an exception for repositories whose modules are developed only with each other. See should you commit go.work for the decision.
A reliable routine
- List all go.mod files.
- For each shipped module, resolve with workspace mode off.
- Scan the result and the go.sum.
- Route findings by module path.
Safeguard scans Go modules and generates SBOMs per project. Try the free scan at https://gold.safeguard.sh/scan.
Quick check
Does a use directive include nested modules?
No. Nested modules need their own use directives.
How do I resolve a module without workspace mode?
Set the GOWORK environment variable to off, which puts the command in a single module context.
Sources
Last reviewed: 19 October 2026.