gary.info

here be dragons

Awesome Go Packages

#go
awesome-go.md

The Actually Useful Go Package List: An Opinionated Guide

Stop googling "best Go web framework" at 2am. I've done it for you.

This isn't another list of GitHub stars. This is what you actually need to know: which packages to use, when to use them, and what choosing them says about your project. Every opinion here comes from production scars.

Web Frameworks: The Big Three (And Why There's Only Three)

Gin - The Default Choice

When to use: You're building an API and want to ship this week When to avoid: You need WebSocket support or hate magic Real talk: Gin is Laravel-energy in Go form. It's not idiomatic, it uses reflection everywhere, and Go purists hate it. It's also in half the production APIs you use daily. Make of that what you will.

Echo - The Thoughtful Alternative

When to use: You want Gin's productivity but cleaner code When to avoid: Your team is already using Gin (not worth the migration) Real talk: Echo is what Gin should have been. Better docs, better middleware story, actual WebSocket support. The v5 release is genuinely exciting (JWT middleware that doesn't suck!).

Fiber - The Speed Demon

When to use: You're building a proxy, gateway, or legitimately need those microseconds When to avoid: Most other times (seriously) Real talk: Built on Fasthttp, which means it's fast but also means you can't use any standard net/http middleware. That's a bigger deal than you think.

The framework you're not considering but should: Standard library + Chi router. More on this below.

HTTP Routers: Where Philosophy Meets Practice

Chi - The Wise Choice

When to use: You want composability and standard net/http compatibility When to avoid: ...honestly, I can't think of when Real talk: Chi is what the standard library router should have been. It's boring in the best way. No benchmarks bragging, no fancy features, just rock-solid routing that composes beautifully.

go
// This is what good Go looks like
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Route("/api", func(r chi.Router) {
    r.Use(authMiddleware)
    r.Get("/users/{id}", getUser)
})

Gorilla/Mux - The Elder Statesman

When to use: Never for new projects When to avoid: Always Real talk: Gorilla is in maintenance mode. It served us well, but it's time to move on. If you're still using it, plan your migration to Chi. Same patterns, better performance, active development.

HttpRouter - The Purist's Choice

When to use: You're building something where every allocation matters When to avoid: You need any middleware or flexibility Real talk: HttpRouter proves a point about performance, but at what cost? No middleware, no regex routes, no route groups. Sometimes constraints are too constraining.

SQL: The Eternal Struggle

Query Builders vs ORMs: Pick Your Fighter

sqlx - The Foundation

When to use: Always, as your base layer When to avoid: Never Real talk: This should be in the standard library. It's not an ORM, it's just database/sql but not terrible. StructScan alone will save you hours.

Squirrel - The Guilty Pleasure

When to use: You need dynamic query building but want to pretend you don't use an ORM When to avoid: Your queries are static (just write SQL) Real talk:

go
// This is more readable than raw SQL, fight me
users := sq.Select("*").From("users").
    Where(sq.Eq{"status": "active"}).
    Where(sq.Gt{"age": 18})

SQLBoiler - The Code Generator

When to use: You want type safety and performance When to avoid: Your schema changes daily Real talk: Database-first design in Go. Generates type-safe code from your schema. It's like having a compiler for your database queries. The generated code is actually readable, which is rare.

GORM - The Controversial Giant

When to use: You're coming from Rails/Django and need familiarity When to avoid: You care about performance or understanding your queries Real talk: GORM is the WordPress of Go ORMs. Incredibly popular, gets the job done, makes experienced developers nervous. V2 is much better, but it's still GORM.

The Migration Situation

golang-migrate - The Standard

When to use: You need migrations (so, always) When to avoid: — Real talk: Supports every database, every source format, embedding migrations in binaries. It's perfect. Stop evaluating alternatives.

Logging: A Surprisingly Political Choice

slog - The Future (Go 1.21+)

When to use: New projects after Go 1.21 When to avoid: You need extreme performance Real talk: It's in the standard library. It's structured. It's good enough. The war is over.

Zap - The Performance King

When to use: You're actually having logging performance problems When to avoid: Most projects (premature optimization) Real talk: Zap's API is... intense. You'll write 5x more code than with other loggers. But if you need those nanoseconds, nothing else comes close.

Zerolog - The Dark Horse

When to use: You want Zap's performance with a saner API When to avoid: Your team is already using something else Real talk: Zerolog proves Zap's API complexity wasn't necessary. Same performance, one-third the cognitive load.

Configuration: More Complex Than It Should Be

Viper - The Kitchen Sink

When to use: You need every configuration source known to humanity When to avoid: You just need environment variables Real talk: Viper does everything. That's the problem. It's 10,000 lines of code to read config files. But it's also everywhere, so you'll probably use it.

envconfig - The Minimalist

When to use: 12-factor apps with environment variables When to avoid: You need config files Real talk:

go
type Config struct {
    Port int envconfig:"PORT" default:"8080"
}
// That's it. That's the whole API.

CLI: Two Philosophies

Cobra - The Generator

When to use: Complex CLIs with subcommands When to avoid: Simple scripts Real talk: Cobra generates boilerplate, which feels un-Go-like. But look at kubectl, hugo, gh - they all use Cobra. Sometimes boilerplate is the point.

urfave/cli - The Library

When to use: You want to write your CLI, not generate it When to avoid: You have deeply nested subcommands Real talk: More idiomatic, less magical. You'll write more code but understand all of it.

Testing: The Part We Pretend To Love

Testify - The Forbidden Fruit

When to use: You want assertions and don't care what the Go team thinks When to avoid: You're a standard library purist Real talk: The Go team says you don't need assertions. They're wrong. assert.Equal(t, expected, actual) is clearer than an if statement. Die on other hills.

GoMock - The Official Mock

When to use: Interface mocking with generation When to avoid: You prefer hand-written test doubles Real talk: Now part of the Go project. Generates mocks from interfaces. The generated code is ugly, but it works.

The New World: AI & Vector Operations

go-openai - The OpenAI Gateway

When to use: You need OpenAI API access When to avoid: — Real talk: Best OpenAI client. Supports streaming, functions, embeddings. The author is incredibly responsive. This is how you maintain an API client.

langchaingo - The Ambitious Port

When to use: You want LangChain patterns in Go When to avoid: You just need simple LLM calls Real talk: This shouldn't work as well as it does. Proof that Go's constraints can improve Python patterns.

Architecture Validators: The Packages That Judge You

Wire - Google's DI

When to use: You want dependency injection but hate runtime magic When to avoid: Small projects Real talk: Generates the DI code you'd write by hand. It's like admitting you want DI but with extra steps.

Fx - Uber's DI

When to use: You want a full application framework When to avoid: You're not building Uber-scale services Real talk: Fx is a lifestyle choice. It changes how you structure everything. Your entire app becomes Fx-shaped.

The Actually Important Meta-Advice

  • Start with the standard library. You'll know when you need more.
  • Your second package should be sqlx. Everything else is negotiable.
  • Pick boring infrastructure packages. Save your innovation tokens for your actual product.
  • Version your tools. go install github.com/some/tool@v1.2.3. Don't let a tool update break your Friday.
  • The best package is the one your team knows. Familiarity beats optimality.
  • If a package has "awesome" benchmarks but terrible docs, run. You're not that smart at 3am.
  • Check the commit history. One commit in 2 years? That's either perfect or dead.
  • The Packages I Didn't Include (And Why)

  • Any blockchain stuff: If you need it, you know where to find it
  • Game development: Different universe, different rules
  • GUI frameworks: We don't talk about Go GUI frameworks
  • That one package your coworker swears by: It's probably fine

Remember: Choosing packages is about tradeoffs, not perfection. Pick boring, pick proven, pick what lets you ship. The only bad choice is analysis paralysis.

Now stop reading and go build something.