Note: This is not Uber’s dig
This article introduces a compile-time dependency injection (DI) tool called dig, which achieves zero reflection and zero runtime overhead through code generation. It shares a name with Uber’s runtime DI library go.uber.org/dig by coincidence only—these are entirely different projects. If you’re looking for Uber’s dig, please visit go.uber.org/dig.
In the Go DI ecosystem, developers have long faced a dilemma: Google Wire offers compile-time safety but has a verbose API and does not support multiple instances of the same type; Uber Fx provides a clean developer experience but relies on runtime reflection, exposing errors only at startup.
dig v1.0.11 breaks this deadlock—it now supports multiple isolated instances of the same type, using Go’s most familiar syntax: named return values + parameter name matching.
Why Multiple Instances?
Real-world projects often need this:
- Database read/write splitting: primary
*sql.DBand replica*sql.DB - HTTP clients with different timeouts: 1s timeout vs 5s timeout
- Multiple implementations of the same interface injected simultaneously
Google Wire’s answer is “not supported.” The official recommendation is to use type aliases to differentiate. This leads to an accumulation of type aliases across the project, making cross-package sharing complicated.
dig does it differently.
Design: Named Return Values + Parameter Name Matching
Providers declare instance names using named return values:
dig.Provide(func() (mainDB *sql.DB) {
return connectToMain()
})
dig.Provide(func() (cacheDB *sql.DB) {
return connectToCache()
})
Consumers reference the corresponding instance via parameter names:
dig.Invoke(func(mainDB *sql.DB, cacheDB *sql.DB) error {
// mainDB → primary connection, cacheDB → cache connection
return nil
})
Unnamed return values remain as the default provider, fully backward compatible:
dig.Provide(func() *sql.DB { return defaultDB })
dig.Invoke(func(db *sql.DB) error {
// Falls back to default when no named provider matches
return nil
})
Key Advantages
| Feature | Wire | Uber Fx | dig v1.0.11 |
|---|---|---|---|
| Compile-time safety | |||
| Zero runtime reflection | |||
| Multiple instances of same type | |||
| Zero new API | - |
dig is the only solution that combines compile-time safety + named instance support + zero new API.
Upgrade
go get github.com/shanjunmei/dig@v1.0.11
go install github.com/shanjunmei/dig/cmd/digen@latest
Compatibility
- Existing code without named return values: Fully compatible, behavior unchanged.
- Existing code with named return values: After upgrade, named return values will act as instance names and participate in dependency matching.
After upgrading, simply run digen. If there are naming mismatches, the tool will report them during go generate with clear fix suggestions:
no provider for type *sql.DB with name "db" required by main.NewService at di.go:20
(available: "mainDB")
đź’ˇ Fix: rename parameter to 'mainDB' (matches the only named provider), or remove the name from the provider's return value to make it default
Just follow the suggestions—no manual scanning needed.
Project: github.com/shanjunmei/dig
Stars, Issues, and PRs are all welcome.