This guide explains why certain dependencies appear in a Go module graph when
using the CUE API. It provides conceptual clarity around how Go’s module system
interacts with CUE packages, the meaning of module dependencies, and how to
interpret module graph output. It is intended for users exploring or embedding
the CUE language in their Go programs.
Overview: Why This Matters
When you add CUE packages like cuelang.org/go/cue, cue/cuecontext, or
cue/load to your Go project, the resulting module graph may include a
surprising number of transitive dependencies. Some of these arise only due to
tests or tools used during development and are not part of the code your
program will actually use. Understanding the difference is essential for:
Auditing your dependencies
Minimizing bloat
Evaluating security risks
The Go Module System: A Quick Recap
The go.mod file: lists required modules for building and testing packages
in your main module.
The go.sum file: records checksums for all modules needed to build and test
all packages, including transitive dependencies.
As a result, modules that only appear in go.sum but not go.mod often exist
solely to satisfy transitive test dependencies. These are not part of your
program’s actual runtime.
Key insight:
Just because a module appears in the dependency graph doesn’t mean it’s part of
your program’s trusted runtime.
Dependency Graphs by CUE Usage Level
In this section we’ll show some of the module dependencies that are pulled in
and explain why they’re present.
In each diagram:
The green “example” box represents your module: the root of the
dependency tree.
Boxes in purple are the core dependencies of your module: code in these
modules can be executed when running your module’s actual code or tests.
These modules will appear in your go.mod file.
Boxes in red highlight modules pulled in only for testing external
packages. They inflate the graph but not the runtime or security surface
area; they will appear in the go.sum file but not the go.mod file.
When importing cuelang.org/go/cue/cuecontext
package example
import _ "cuelang.org/go/cue/cuecontext"
Includes the CUE evaluator and standard library.
Adds standard library definitions (such as for JSON/YAML encoding/decoding,
math functions).
We recognize that the current design may lead to dependency noise. For example,
if all you are doing is compiling CUE which does not marshal or unmarshal YAML,
it should be possible to evaluate it without using a YAML dependency. Several
mitigations are either planned or under consideration:
Lean Construction API
We could add a constructor for a bare *cue.Context that would avoid standard
library dependencies.
Useful for simple validation and evaluation tasks that do not need the CUE
standard library.
Trivially implemented without radically changing the existing CUE API.
This is what a minimal dependency graph looks like that only imports
cuelang.org/go/cue:
The Go module system offers deterministic builds and strong integrity
guarantees, but its all-encompassing view of test and tool dependencies can be
misleading when assessing runtime requirements. This guide aims to help you
discern what’s necessary and what’s incidental, and to look forward to a more
modular future for CUE.
Key takeaways:
Review your go.mod file for dependencies that will be added to your
program/service.
Remember that not all packages in these modules will necessarily be used.
Do not be overly concerned by entries in go.sum itself.