Dev Skills

The packages everyone actually uses

The well-known third-party libraries, what each is for, and when the standard library is still the better choice.

Topic 50 of 98 · 10 min to read · 50 min to build
After this topic you can
  • Explain when the standard library is a better choice than a popular third-party package.
  • Judge a package before adding it, using maintenance, licence and dependency count.
  • Name the usual library for routing, databases, config, logging and testing.

Why this topic exists

Go has an unusually strong standard library, so for most problems the advice is use the stdlib. That is why the three projects ahead in this track need only four dependencies.

But you will read other people's code, join teams with existing choices, and hit problems the stdlib does not solve. This is the map: what the well-known packages are, what each one is for, and, where one exists, the stdlib alternative to try first.

How to judge a package before you add it

terminal — the checks worth running before you commit a new dependency
go get example.com/thing
go mod graph | wc -l # how much did that just pull in?
go mod why -m example.com/thing
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
go doc example.com/thing # read the API before you build on it
  • Is it still alive? Look at the last commit and the open issue count on GitHub, not the star count. Stars measure a blog post from 2019.
  • What does it drag in? Run go mod graph after adding it. A logging library that pulls in forty modules is a supply-chain decision, not a convenience.
  • Could you write it in an afternoon? If yes, and it is not security-critical, write it. Every dependency is code you must keep updating.
  • Does it wrap something you should understand? An ORM you adopt before you know SQL tends to cost more than it saves.
  • Check `pkg.go.dev` for the docs and the import count, and run `govulncheck` after adding anything.

Web frameworks and routing

PackageWhat it isTry the stdlib first
net/httpThe standard library. Since Go 1.22 it routes on method and path parameters.— this *is* the answer for most services
chiA thin router on top of net/http. Middleware chaining, route groups, sub-routers.http.ServeMux plus your own middleware
ginThe most popular full framework. Its own context type, binding, validation.net/http: gin handlers take *gin.Context, not the standard handler signature
echoSimilar to gin, slightly cleaner API.net/http
fiberExpress-style API built on fasthttp, not net/http.net/http: fiber cannot use standard middleware directly
gorilla/muxThe classic router. Was unmaintained for a while, now revived.http.ServeMux does this in 1.22+
Note: On a new service today, start with net/http. Reach for chi when you want route groups and middleware helpers without leaving the standard interfaces. Reach for gin or echo when the team already uses them.

Databases

PackageWhat it isWhen it is the right call
database/sqlStandard library. The common interface SQL drivers implement.the default; sqlx, GORM and most drivers plug into it
pgxThe Postgres driver. Used directly, or through database/sql.any Postgres project; this is the default
go-sql-driver/mysqlThe MySQL driver.MySQL projects
sqlxA thin layer over database/sql that scans rows into structs.when hand-writing Scan calls gets tedious
sqlcGenerates type-safe Go from your SQL. You keep writing SQL.you want typed Go and still want to write the SQL
entA schema-as-code entity framework, first built at Facebook. Powerful, opinionated.complex relational graphs
GORMA full ORM. Auto-migration, hooks, associations.CRUD-heavy apps where SQL control matters less
golang-migrate / gooseSchema migration runners.every project with a database
go-redisThe Redis client.caching, rate limiting, queues

Configuration and CLIs

PackageWhat it isTry first
os.Getenv + flagStandard library. Environment variables and command-line flags.— enough for most services
godotenvLoads a .env file in development.used in this track; small, with no dependencies of its own
viperConfig from files, env, flags and remote stores, merged together.when you need layered config; it pulls in many dependencies
kelseyhightower/envconfigFills a struct from environment variables using tags.a light middle ground
cobraThe CLI framework behind kubectl, hugo and gh. Subcommands, help, completion.multi-command CLIs
urfave/cliA lighter CLI framework.simpler CLIs

Logging

PackageWhat it isVerdict
log/slogStandard library since Go 1.21. Structured, levelled, with handlers.start here; this is what the track uses
zapUber's logger. Very fast, more ceremony.when profiling shows logging is your bottleneck
zerologZero-allocation JSON logger, chained API.similar case to zap
logrusThe original structured logger. In maintenance mode.you will meet it in old code; do not start with it

Testing

PackageWhat it isNote
testingStandard library. Tests, subtests, benchmarks, fuzzing.no framework needed; see the Testing topic
testifyAssertions (assert, require) plus mocks and suites.the most common add-on; require.NoError is the draw
google/go-cmpDeep comparison built for tests, with readable diffs.better than reflect.DeepEqual for structs
testcontainers-goStarts real Postgres, Redis or Kafka in Docker for a test.testing a repository layer against a real database
ory/dockertestLighter alternative to testcontainers.same job, fewer features
uber-go/mockGenerated mocks from interfaces (successor to golang/mock).hand-written fakes are usually smaller
goleakFails a test if goroutines are still running at the end.catches leaks that no other test would notice
Watch out: The one to think twice about is testify's mock and suite packages. Assertions are fine and save real typing. Generated mocks and test suites tend to hide what a test is doing. Go interfaces are small and implicit, so a hand-written fake is usually shorter than the mock setup.

Concurrency helpers

PackageWhat it isWhy it matters
sync, contextStandard library. Mutex, WaitGroup, Once, cancellation.covers most of what you need
golang.org/x/sync/errgroupRun goroutines, collect the first error, cancel the rest. SetLimit bounds concurrency.the one worth adding; see the Concurrency topics
golang.org/x/sync/singleflightCollapses duplicate concurrent calls into one.cache stampede protection in ~5 lines
golang.org/x/sync/semaphoreA weighted semaphore.when a plain channel-as-semaphore is not enough
golang.org/x/time/rateToken-bucket rate limiter.used in this track for rate limiting
sourcegraph/concStructured concurrency helpers with panic handling built in.newer; nice, but errgroup covers most cases

Everything else you will meet

PackageWhat it is for
google/uuidUUID generation. The near-universal choice.
shopspring/decimalExact decimal arithmetic for money, when integer cents is not enough.
go-playground/validatorStruct validation driven by tags. Common with gin.
golang-jwt/jwtJSON Web Tokens. Used in this track.
golang.org/x/crypto/bcryptPassword hashing. Used in this track.
golang.org/x/oauth2OAuth2 clients for Google, GitHub and friends.
prometheus/client_golangMetrics: counters, histograms, the /metrics endpoint.
open-telemetry/opentelemetry-goTraces and metrics across services.
grpc/grpc-go + protobufgRPC services and protocol buffers.
segmentio/kafka-go, IBM/saramaKafka clients.
nats-io/nats.goNATS messaging.
hibiken/asynqBackground job queue backed by Redis.
uber-go/automaxprocsSets GOMAXPROCS from the container CPU limit. Not needed from Go 1.25, which does this itself on Linux.
samber/loLodash-style generic helpers. Check slices and maps first.
spf13/aferoA filesystem interface, so you can fake the disk in tests.
swaggo/swag, oapi-codegenOpenAPI docs from comments, or Go from an OpenAPI spec.

Tools you install, rather than import

terminal
# linting and safety
go install honnef.co/go/tools/cmd/staticcheck@latest # the best-value linter
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
go install golang.org/x/vuln/cmd/govulncheck@latest # official, low noise
# development
go install github.com/air-verse/air@latest # live reload
go install github.com/go-delve/delve/cmd/dlv@latest # the debugger
go install golang.org/x/perf/cmd/benchstat@latest # honest benchmark comparison
go install github.com/rakyll/hey@latest # simple load testing
# database
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
These are binaries, not imports. Installed this way, they do not appear in your go.mod. (Since Go 1.24, `go get -tool` can pin a tool in go.mod instead.)

What a typical production service actually imports

A realistic dependency list for a company's Go API is short, like this one.

go.mod — a normal, boring, production service
require (
github.com/go-chi/chi/v5 v5.2.3 // routing niceties
github.com/jackc/pgx/v5 v5.7.5 // Postgres
github.com/golang-jwt/jwt/v5 v5.3.0 // tokens
github.com/google/uuid v1.6.0 // ids
github.com/prometheus/client_golang v1.23.2 // metrics
golang.org/x/crypto v0.43.0 // bcrypt
golang.org/x/sync v0.17.0 // errgroup
)
// Everything else — HTTP, JSON, SQL interface, logging, context,
// testing, templates, crypto — comes with Go.
Worth knowing: If your go.mod has 200 lines, that is worth a look. Go culture leans hard towards fewer dependencies, and a reviewer may ask why each one is there. "Because the standard library already does it" is a common reason to remove one.
The short version
  • Start with the standard library. It covers HTTP, SQL, JSON, logging, testing and crypto.
  • net/http routes on method and path since 1.22, so a web framework is now a preference, not a need.
  • The few genuinely worth adding: a database driver, errgroup, bcrypt, a JWT library, and metrics.
  • Judge a package by its last commit and what it drags in — not by its star count.
Remember: Every dependency is code you have to update, audit and explain for as long as you keep it. The stdlib rarely needs justifying.
Build this before moving on
Open the go.mod of a Go project you did not write and look up every dependency on pkg.go.dev. For each one, decide whether the standard library could have done it.
Then try these in your own editor
  1. 1Add gin to a scratch project, run go mod graph | wc -l, then do the same for chi. Compare.
  2. 2Rewrite one reflect.DeepEqual test assertion with google/go-cmp and compare the failure output.
  3. 3Replace a hand-rolled worker pool with errgroup.SetLimit and count the lines removed.
  4. 4Run govulncheck ./... on any project you have and read what it reports.
Check yourselfTake the Modules and packages test