How do you do dependency injection in Go? Compare manual constructor wiring with google/wire and uber/fx.
Question 557MediumGo 1.22 to 1.25
Idiomatic DI in Go means constructors that accept interfaces or concrete dependencies as parameters, all wired explicitly in main. No container is needed. The dependency graph is visible, checked at compile time, and easy to follow with "go to definition".
func main() {
cfg := config.MustLoad()
db, err := sql.Open("pgx", cfg.DSN)
if err != nil {
log.Fatal(err)
}
defer db.Close()
repo := postgres.NewOrderRepo(db)
svc := order.NewService(repo, clock.Real{})
srv := httpapi.NewServer(svc, cfg.Addr)
log.Fatal(srv.ListenAndServe())
}
- google/wire: compile-time code generation. You declare providers and a
wire.Build(...)injector, and wire generates exactly the manual code above. Missing or duplicate providers fail at generate time, and there is no runtime reflection. The project is considered feature-complete and changes little. - uber/fx: a runtime container built on reflection (
dig). You getfx.Provide/fx.Invoke, lifecycle hooks (OnStart/OnStop) and modules. Graph errors show up at startup, not at compile time, and following the call flow takes more effort.
Verdict: manual wiring is right for most services. Consider wire when main.go grows to hundreds of lines of plumbing. fx suits large organizations that standardize many services with shared modules and lifecycle. Gotcha: avoid a global service locator. Keep interfaces small and define them at the consumer so tests can use fakes.
More on Go Idioms, Design Patterns & Language Design
- Q555Does Go do tail-call optimization? What happens with deep recursion, and what does "goroutine stack exceeds 1000000000-byte limit" mean?
- Q556How do you structure a large Go project (cmd/, internal/, pkg/ debate)? How should packages be named and split to avoid stutter and cycles?
- Q558How would you implement the decorator, strategy, and adapter patterns idiomatically in Go?
- Q559How do you implement a circuit breaker and bulkhead in Go? What state machine and concurrency concerns are involved?
- Q560What are the uses of the blank identifier (_)? Explain import _, var _ = , _ = x and blank struct fields.
- Q561What are anonymous structs and struct tags? When would you use an anonymous struct in tests or JSON handling?