Table of contents
nurago is one Go module containing 70 packages, several of which wrap large third-party SDKs. The obvious worry is that importing one package drags all of that into the binary. It does not.
How It Works
Go resolves dependencies per package. The require list in a module’s go.mod is the set of modules that some package in it may need. What ends up in your build is what your own imports reach, transitively, and go mod tidy then prunes your go.sum and module graph to that set.
Importing pkg/backoff therefore adds no AWS SDK, Kafka, Redis, or OpenTelemetry code to your build, even though other packages in nurago require those modules.
The Numbers
40 of the 70 packages reach no external module at all, using nothing beyond the Go standard library:
backoff, countrycode, countryphone, decint, dnscache, encode, encrypt, enumbitmap, enumcache, enumdb, errutil, filter, httpclient, httpretrier, ipify, logutil, maputil, metrics, mysqllock, numtrie, paging, periodic, phonekeypad, random, redact, retrier, sfcache, sliceutil, sqlconn, sqltransaction, sqlutil, stringmetric, strsplit, threadsafe, timeutil, traceid, tsmap, tsslice, typeutil, uhex.
Several of those would normally be assumed to carry dependencies. The outbound HTTP client, the HTTP retrier, the retry engine, the DNS cache, the log redactor, the metrics contract, the SQL connection and transaction helpers, and the MySQL distributed lock all run on the standard library alone.
The heaviest imports are the ones wrapping an ecosystem: metrics/opentel pulls 28 modules, config (Viper) pulls 12, metrics/prometheus pulls 10. Those arrive only when you import them.
Every package page on this site states its own footprint, listing the external modules by name. See /packages/.
Verify It Yourself
For any package:
go list -deps -f '{{if .Module}}{{.Module.Path}}{{end}}' \
github.com/tecnickcom/nurago/pkg/backoff | sort -u
For your own binary, the same question asked of your main package:
go list -deps -f '{{if .Module}}{{.Module.Path}}{{end}}' ./cmd/myservice | sort -u
And to see why a specific module is in your build at all:
go mod why -m github.com/aws/aws-sdk-go-v2
Practical Consequences
The metrics contract is standard-library-only, and the weight sits in whichever implementation you pick: opentel, prometheus, or statsd. Library code can depend on metrics.Client and emit measurements without imposing a backend on its callers.
Logging works the same way. logutil builds log/slog handlers on the standard library alone; logsrv adds zerolog when you want its encoder. Application code depends on log/slog either way.
Where build size or supply-chain surface matters, prefer the standard-library-only packages, and keep the heavy imports at the composition root of the service instead of spreading them through internal packages.
Previous: /docs/service-scaffolding/
Overview: /docs/
Next: /docs/observability/