Standard Library Best Practices
Prefer stdlib until a clear gap; know deprecation paths.
Search across all documentation pages
Prefer stdlib until a clear gap; know deprecation paths.
Apply these rules in code review, module templates, and dependency ADRs so every Go service gets predictable upgrades and smaller attack surfaces.
go vet, staticcheck, import guards) where possible.go mod tidy and smaller SBOMs.crypto/tls and crypto/rand track Go security releases.govulncheck on modules that duplicate stdlib roles. Catches known issues in overlapping HTTP or JSON libraries.io.Copy and bound untrusted input with io.LimitReader. Prevents OOM on uploads and malicious bodies.filepath for OS paths and path only for URL-like slashes. Windows deployments break on hardcoded /.bufio.Scanner for line input; set buffer caps for long tokens. Avoids silent Err on wide log lines.filepath.WalkDir instead of legacy Walk. Cuts extra Stat syscalls on large trees.time.Location at display. DST-safe instants across regions.context.Context as the first parameter on blocking APIs. Enables HTTP and RPC cancellation uniformly.cancel() from WithTimeout and WithCancel via defer. Releases timer resources promptly.time.Sleep in servers with select on ctx.Done(). Shutdown hooks finish within grace periods.log/slog for new services with JSON handlers in production. Operators parse levels and attributes reliably.MustCompile wastes CPU under load.html/template, not text/template. Contextual escaping blocks XSS from user fields.log for legacy boundaries until migrated. Mixed styles are fine short term; plan slog at main.crypto/rand, never math/rand/v2. Predictable IDs become account takeover vectors.math/rand/v2 with explicit Rand values in libraries. Removes hidden global state and flaky parallel tests.gzip.Writer to flush footers before uploading archives. Truncated gzip breaks downstream consumers.MinVersion to 1.2 or higher on listeners. Documents cipher posture for security review.PingContext databases during startup before accepting traffic. Surfaces bad DSNs at deploy time, not on first user.SetMaxOpenConns and SetConnMaxLifetime from DB capacity math. Protects shared database instances from one service.QueryContext and ExecContext in HTTP handlers. Honors r.Context() deadlines automatically.http.Client instances with timeouts per upstream. Never rely on http.DefaultClient in servers.ReadHeaderTimeout on every production http.Server. Blocks slowloris stalls before handlers execute.pprof.Do for attributable flame graphs. Otherwise profiles show anonymous runtime frames.debug.SetMemoryLimit with Kubernetes memory limits. Leave headroom for stacks and off-heap allocations.When stdlib lacks the capability (ORM relation graphs, advanced validation DSLs, vendor SDKs) or when organizational standards mandate a shared wrapper.
Record the gap in README or ADR text.
Migrate at service boundaries starting with main.
Libraries should accept *slog.Logger parameters rather than forcing global defaults.
Use import linters (depguard, custom go vet analyzers) to block duplicate HTTP frameworks in the same module without an exemption file.
New code uses math/rand/v2 with explicit sources.
Legacy math/rand global functions remain for compatibility but avoid them in libraries.
Routers are fine when they export http.Handler and justify ergonomics.
Still apply stdlib timeout, client, and context rules underneath.
Often yes for embedded sqlite writers.
Server databases like PostgreSQL need higher pools tuned to instance limits.
After each Go minor release and during annual dependency audits.
New stdlib packages may close gaps that previously required modules.
Yes.
embed replaces asset-copy build steps; slog replaces ad-hoc JSON log formatters for many services.
testing and httptest cover most needs.
Add testify or similar only when table assertions materially improve readability and team consensus exists.
Keep an EXCEPTIONS.md or inline ADR links in go.mod comments listing approved non-stdlib packages and the capability gap filled.
No.
google.golang.org/grpc fills a protocol stdlib does not ship; still use stdlib context, tls, and logging patterns alongside it.
Importing a full web framework before exhausting net/http, slog, and database/sql defaults.
Start minimal; add layers when pain is measured, not anticipated.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026