How static analysis works
gonx builds the Nx project graph by parsing Go source files directly with
tree-sitter. This approach does not require Go
to be installed, which means nx graph and affected-task detection work even in
environments without a Go toolchain.
Why tree-sitter
Section titled “Why tree-sitter”A Go toolchain is not always available in every environment that runs Nx — CI
runners, remote caches, or containers may have Node but not Go. Parsing Go
source with tree-sitter lets gonx extract import statements and build the
project graph without invoking go list or any external process. The parser is
a WebAssembly binary loaded from the web-tree-sitter and tree-sitter-go
packages, so it runs anywhere Node runs.
How the graph is built
Section titled “How the graph is built”The dependency detection runs in four stages:
-
Module discovery — gonx scans all Nx projects for
go.modfiles and extracts module paths and replace directives. Eachgo.moddefines a Go module; its module path is the key used to resolve imports. -
Import extraction —
.gofiles are parsed with tree-sitter to extractimportstatements.vendor/andtestdata/directories are excluded. -
Dependency resolution — imports are resolved to Nx projects using longest-prefix matching. For example, importing
github.com/myorg/shared/utilsresolves to the project whosego.moddeclaresmodule github.com/myorg/shared. -
Replace directives —
replacedirectives ingo.modare scoped per-project. A replace directive in one project’sgo.modonly affects that project’s imports, matching Go’s own module resolution semantics.
Build constraints
Section titled “Build constraints”gonx honors //go:build and legacy // +build constraints. The dependency
graph is computed against the host platform’s GOOS/GOARCH — a file gated to
a different platform contributes no edges on the host.
Supported in the constraint expression:
//go:buildmodern boolean form:&&,||,!, parentheses// +buildlegacy form (space-separated terms = OR, comma-separated within a term = AND,!per-term negation, multiple lines AND’d)unixpseudo-tag (matches Linux, Darwin, the BSDs, Solaris, AIX, and the full set Go ships ininternal/syslist.UnixOS)GOOSvalues (linux,darwin,windows, …) andGOARCHvalues (amd64,arm64,386, …)- User-defined tags, plus
cgoandgo1.Npolicy
Filename-based suffixes are also honored, matching Go’s go/build algorithm:
name_<GOOS>.go, name_<GOARCH>.go, name_<GOOS>_<GOARCH>.go, and any of
those with a trailing _test before .go. Note that unix is recognized only
as an in-source build tag, not as a filename suffix — Go itself doesn’t
treat foo_unix.go as unix-gated, and neither does gonx.
Edge-case behavior
Section titled “Edge-case behavior”go1.Xversion tags evaluate totrueby default (no Go compiler is handy to consult; over-including is safer than under-including for graph purposes).- The
cgopseudo-tag evaluates tofalseby default — static analysis never invokes cgo. - A malformed constraint expression falls back to “include the file” rather than failing graph construction.
Limitations
Section titled “Limitations”- No cgo support: the
import "C"pseudo-import is filtered out. - No dynamic imports: only static
importstatements are detected.
Disabling dependency detection
Section titled “Disabling dependency detection”To disable Go dependency detection entirely, set
skipGoDependencyCheck: true in the plugin options:
{
"plugins": [
{
"plugin": "@naxodev/gonx",
"options": {
"skipGoDependencyCheck": true
}
}
]
}
See the plugin options reference for all configuration options.
Troubleshooting
Section titled “Troubleshooting”Dependencies not detected
Section titled “Dependencies not detected”- Verify both projects have
go.modfiles. - Check that the module paths match the import statements.
- Ensure the importing project has a
replacedirective pointing to the local project (required when not usinggo.work).
Debugging
Section titled “Debugging”NX_VERBOSE_LOGGING=true nx graph
Next steps
Section titled “Next steps”- Plugin options —
skipGoDependencyCheckand other settings - Quick start — see the project graph in action
- Contributing — how to contribute to gonx