$npx -y skills add samber/cc-skills-golang --skill golang-uber-digImplements 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 codeb
| 1 | **Persona:** You are a Go architect wiring an application graph with dig. You keep the container at the composition root, depend on interfaces not concrete types, and treat constructor errors as first-class failures. |
| 2 | |
| 3 | # Using uber-go/dig for Dependency Injection in Go |
| 4 | |
| 5 | Reflection-based DI toolkit, designed to power application frameworks (it is the engine behind `uber-go/fx`) and resolve object graphs during startup. |
| 6 | |
| 7 | **Official Resources:** |
| 8 | |
| 9 | - [pkg.go.dev/go.uber.org/dig](https://pkg.go.dev/go.uber.org/dig) |
| 10 | - [github.com/uber-go/dig](https://github.com/uber-go/dig) |
| 11 | |
| 12 | This skill is not exhaustive. Please refer to library documentation and code examples for more information. For Go package docs, symbols, versions, importers, and known vulnerabilities, → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`) — prefer it over Context7 for Go package facts. To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See `samber/cc-skills-golang@golang-gopls` skill (`gopls`). Context7 remains a fallback for docs not indexed on pkg.go.dev. |
| 13 | |
| 14 | ```bash |
| 15 | go get go.uber.org/dig |
| 16 | ``` |
| 17 | |
| 18 | ## dig vs. fx |
| 19 | |
| 20 | fx is built on dig and shares the same container engine — the DI primitives (`Provide`, `Invoke`, `In`/`Out` structs, named values, value groups) are identical. `fx.In`/`fx.Out` are re-exports of `dig.In`/`dig.Out`. |
| 21 | |
| 22 | What fx adds on top of dig: |
| 23 | |
| 24 | | Concern | dig | fx | |
| 25 | | --- | --- | --- | |
| 26 | | DI container | ✅ `dig.New()` | ✅ (embedded) | |
| 27 | | Lifecycle hooks | ❌ | ✅ `fx.Lifecycle` OnStart/OnStop | |
| 28 | | Module system | ❌ | ✅ `fx.Module` with scoped decorators | |
| 29 | | Signal-aware run loop | ❌ | ✅ `app.Run()` blocks on SIGINT/SIGTERM | |
| 30 | | Structured event logging | ❌ | ✅ `fx.WithLogger` / `fxevent` | |
| 31 | | Startup/shutdown timeout | ❌ | ✅ `fx.StartTimeout` / `fx.StopTimeout` | |
| 32 | |
| 33 | **Choose dig** when you need the wiring graph only: CLI tools, libraries exposing a container to callers, test harnesses, or embedding DI into an existing app that manages its own lifecycle. |
| 34 | |
| 35 | **Choose fx** for long-running services (HTTP servers, workers, daemons) — lifecycle and signal handling are non-negotiable there. See `samber/cc-skills-golang@golang-uber-fx` skill. |
| 36 | |
| 37 | ## Container |
| 38 | |
| 39 | ```go |
| 40 | import "go.uber.org/dig" |
| 41 | |
| 42 | c := dig.New() |
| 43 | ``` |
| 44 | |
| 45 | Useful options: `dig.DeferAcyclicVerification()` (faster startup), `dig.RecoverFromPanics()` (turn panics into `dig.PanicError`), `dig.DryRun(true)` (validate without invoking). |
| 46 | |
| 47 | ## Provide and Invoke |
| 48 | |
| 49 | ```go |
| 50 | // Register a constructor — lazy, only runs when its output is needed |
| 51 | err := c.Provide(func(cfg *Config) (*sql.DB, error) { |
| 52 | return sql.Open("postgres", cfg.DSN) |
| 53 | }) |
| 54 | |
| 55 | // Pull a service out of the container by asking for it as a function parameter |
| 56 | err = c.Invoke(func(db *sql.DB) error { |
| 57 | return db.Ping() |
| 58 | }) |
| 59 | ``` |
| 60 | |
| 61 | Constructors are **lazy** and **memoized**: each output type is built once and shared (singleton per container). `Provide` errors at registration if the constructor is malformed; `Invoke` returns the constructor's error wrapped with the dependency path that triggered it. |
| 62 | |
| 63 | A dig constructor is any function. Inputs are dependencies, outputs are provided types. `error` (last return) signals construction failure. Follow "accept interfaces, return structs". |
| 64 | |
| 65 | ## Parameter Objects with `dig.In` |
| 66 | |
| 67 | Once a constructor has 4+ dependencies, embed `dig.In` to group them as struct fields and tag fields: |
| 68 | |
| 69 | ```go |
| 70 | type HandlerParams struct { |
| 71 | dig.In |
| 72 | |
| 73 | Logger *zap.Logger |
| 74 | DB *sql.DB |
| 75 | Cache *redis.Client `optional:"true"` // zero value if not provided |
| 76 | DBRO *sql.DB `name:"readonly"` // named dependency |
| 77 | Routes []http.Handler `group:"routes"` // value group |
| 78 | } |
| 79 | |
| 80 | func NewHandler(p HandlerParams) *Handler { /* ... */ } |
| 81 | ``` |
| 82 | |
| 83 | Tags: `name:"..."`, `optional:"true"`, `group:"..."`. |
| 84 | |
| 85 | ## Result Objects with `dig.Out` |
| 86 | |
| 87 | Return several values from one constructor and attach `name`/`group` tags to results: |
| 88 | |
| 89 | ```go |
| 90 | type Conn |