Loading...
Loading...
Implements dependency injection in Golang using uber-go/dig — reflection-based container, Provide/Invoke, dig.In/dig.Out parameter and result objects, named values, value groups, optional dependencies, scopes, and Decorate. Apply when using or adopting uber-go/dig, when the codebase imports `go.uber.org/dig`, or when wiring an application graph at startup. For higher-level lifecycle and modules, see `samber/cc-skills-golang@golang-uber-fx` skill.
npx skill4agent add samber/cc-skills-golang golang-uber-diguber-go/fxgo get go.uber.org/digWhen to choose dig over fx. Use raw dig only when you need the wiring graph and not fx's lifecycle, signal handling, or app boot semantics. For most production apps, prefer fx (skill) — it adds lifecycle hooks, modules, and signal-awaresamber/cc-skills-golang@golang-uber-fxon top of the same dig engine.Run()
import "go.uber.org/dig"
c := dig.New()dig.DeferAcyclicVerification()dig.RecoverFromPanics()dig.PanicErrordig.DryRun(true)// Register a constructor — lazy, only runs when its output is needed
err := c.Provide(func(cfg *Config) (*sql.DB, error) {
return sql.Open("postgres", cfg.DSN)
})
// Pull a service out of the container by asking for it as a function parameter
err = c.Invoke(func(db *sql.DB) error {
return db.Ping()
})ProvideInvokeerrordig.Indig.Intype HandlerParams struct {
dig.In
Logger *zap.Logger
DB *sql.DB
Cache *redis.Client `optional:"true"` // zero value if not provided
DBRO *sql.DB `name:"readonly"` // named dependency
Routes []http.Handler `group:"routes"` // value group
}
func NewHandler(p HandlerParams) *Handler { /* ... */ }name:"..."optional:"true"group:"..."dig.Outnamegrouptype ConnResult struct {
dig.Out
ReadWrite *sql.DB `name:"primary"`
ReadOnly *sql.DB `name:"readonly"`
}
func NewConnections(cfg *Config) (ConnResult, error) { /* ... */ }dig.Namec.Provide(NewPrimaryDB, dig.Name("primary"))
c.Provide(NewReadOnlyDB, dig.Name("readonly"))name:"primary"name:"readonly"dig.Intype RouteResult struct {
dig.Out
Handler http.Handler `group:"routes"`
}
func NewUserHandler(db *sql.DB) RouteResult { /* ... */ }
func NewPostHandler(db *sql.DB) RouteResult { /* ... */ }
type ServerParams struct {
dig.In
Routes []http.Handler `group:"routes"`
},flattengroup:"routes,flatten"dig.Asc.Provide(NewPostgresDB, dig.As(new(Database), new(io.Closer)))
// Consumers ask for Database or io.Closer; *PostgresDB stays hidden.func main() {
c := dig.New()
must(c.Provide(NewConfig))
must(c.Provide(NewLogger))
must(c.Provide(NewDatabase))
must(c.Provide(NewServer))
err := c.Invoke(func(srv *http.Server) error {
return srv.ListenAndServe()
})
if err != nil {
log.Fatal(err)
}
}
func must(err error) { if err != nil { panic(err) } }samber/cc-skills-golang@golang-uber-fx*dig.Containermain()dig.Asdig.Inc.Providec.InvokeDryRun(true)| Mistake | Fix |
|---|---|
| Passing the container into services | The container belongs to |
Two providers for the same type without | dig errors at |
Ignoring | Wrap each |
| Using groups when ordering matters | Groups are unordered. If order matters (middleware chain, migration sequence), provide an explicit ordered slice with one constructor. |
| Constructors with side effects on import | Keep |
DecorateInvokesamber/cc-skills-golang@golang-uber-fxsamber/cc-skills-golang@golang-dependency-injectionsamber/cc-skills-golang@golang-samber-dosamber/cc-skills-golang@golang-google-wiresamber/cc-skills-golang@golang-structs-interfacessamber/cc-skills-golang@golang-testing