Skip to main content
ClaudeWave
Skill2.1k repo starsupdated 3d ago

golang-uber-dig

The golang-uber-dig skill teaches dependency injection using uber-go/dig, a reflection-based container that wires application graphs at startup. Use it when adopting dig for lazy constructor invocation, managing object dependencies through Provide and Invoke, handling named values and optional dependencies, or when the codebase imports go.uber.org/dig. For long-running services requiring lifecycle hooks and signal handling, use the golang-uber-fx skill instead.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/samber/cc-skills-golang /tmp/golang-uber-dig && cp -r /tmp/golang-uber-dig/skills/golang-uber-dig ~/.claude/skills/golang-uber-dig
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

**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.

# Using uber-go/dig for Dependency Injection in Go

Reflection-based DI toolkit, designed to power application frameworks (it is the engine behind `uber-go/fx`) and resolve object graphs during startup.

**Official Resources:**

- [pkg.go.dev/go.uber.org/dig](https://pkg.go.dev/go.uber.org/dig)
- [github.com/uber-go/dig](https://github.com/uber-go/dig)

This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.

```bash
go get go.uber.org/dig
```

## dig vs. fx

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`.

What fx adds on top of dig:

| Concern | dig | fx |
| --- | --- | --- |
| DI container | ✅ `dig.New()` | ✅ (embedded) |
| Lifecycle hooks | ❌ | ✅ `fx.Lifecycle` OnStart/OnStop |
| Module system | ❌ | ✅ `fx.Module` with scoped decorators |
| Signal-aware run loop | ❌ | ✅ `app.Run()` blocks on SIGINT/SIGTERM |
| Structured event logging | ❌ | ✅ `fx.WithLogger` / `fxevent` |
| Startup/shutdown timeout | ❌ | ✅ `fx.StartTimeout` / `fx.StopTimeout` |

**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.

**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.

## Container

```go
import "go.uber.org/dig"

c := dig.New()
```

Useful options: `dig.DeferAcyclicVerification()` (faster startup), `dig.RecoverFromPanics()` (turn panics into `dig.PanicError`), `dig.DryRun(true)` (validate without invoking).

## Provide and Invoke

```go
// 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()
})
```

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.

A dig constructor is any function. Inputs are dependencies, outputs are provided types. `error` (last return) signals construction failure. Follow "accept interfaces, return structs".

## Parameter Objects with `dig.In`

Once a constructor has 4+ dependencies, embed `dig.In` to group them as struct fields and tag fields:

```go
type 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 { /* ... */ }
```

Tags: `name:"..."`, `optional:"true"`, `group:"..."`.

## Result Objects with `dig.Out`

Return several values from one constructor and attach `name`/`group` tags to results:

```go
type ConnResult struct {
    dig.Out

    ReadWrite *sql.DB `name:"primary"`
    ReadOnly  *sql.DB `name:"readonly"`
}

func NewConnections(cfg *Config) (ConnResult, error) { /* ... */ }
```

## Named Values

Two providers of the same type collide. Disambiguate with `dig.Name`:

```go
c.Provide(NewPrimaryDB,  dig.Name("primary"))
c.Provide(NewReadOnlyDB, dig.Name("readonly"))
```

Consume by adding `name:"primary"` / `name:"readonly"` to a `dig.In` field.

## Value Groups

Many providers, one consumer slice — typical for HTTP handlers, health checks, migrations:

```go
type 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"`
}
```

**Flatten** — append `,flatten` (e.g. `group:"routes,flatten"`) to unwrap a slice instead of nesting it. Group order is **not guaranteed**; if order matters, provide an explicit ordered slice from a single constructor.

## Provide as Interface (`dig.As`)

Register a concrete constructor and expose it under one or more interfaces without a separate adapter:

```go
c.Provide(NewPostgresDB, dig.As(new(Database), new(io.Closer)))
// Consumers ask for Database or io.Closer; *PostgresDB stays hidden.
```

## Full Application Example

```go
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) } }
```

dig has **no built-in lifecycle**. If you need OnStart/OnStop hooks, signal handling, and graceful shutdown, use fx — see `samber/cc-skills-golang@golang-uber-fx` skill.

For Decorate, Scopes, optional deps, error helpers, and Visualize, see [advanced.md](./references/advanced.md).

## Best Practices

1. Keep the container at the composition root — never pass `*dig.Container` as a parameter; treat it like a plumbing detail of `main()`. Service-locator patterns defeat the testability gains of DI.
2. Depend on interfaces, not concrete types — lets you swap implementations in tests without touching production code, and lets you use `dig.As` to expose
golang-benchmarkSkill

Golang benchmarking, profiling, and performance measurement. Use when writing, running, or comparing Go benchmarks, profiling hot paths with pprof, interpreting CPU/memory/trace profiles, analyzing results with benchstat, setting up CI benchmark regression detection, or investigating production performance with Prometheus runtime metrics. Also use when the developer needs deep analysis on a specific performance indicator - this skill provides the measurement methodology, while `samber/cc-skills-golang@golang-performance` provides the optimization patterns.

golang-cliSkill

Golang CLI application development. Use when building, modifying, or reviewing a Go CLI tool — especially for command structure, flag handling, configuration layering, version embedding, exit codes, I/O patterns, signal handling, shell completion, argument validation, and CLI unit testing. Also triggers when code uses cobra, viper, or urfave/cli. For cobra-specific APIs → See `samber/cc-skills-golang@golang-spf13-cobra` skill; for viper configuration layering → See `samber/cc-skills-golang@golang-spf13-viper` skill.

golang-code-styleSkill

Golang code style conventions — line length and breaking, variable declarations, control flow clarity, when comments help vs hurt. Use when writing or reviewing Go code, asking about style or clarity, or establishing project coding standards. Not for naming conventions (→ See `samber/cc-skills-golang@golang-naming` skill), linter configuration (→ See `samber/cc-skills-golang@golang-lint` skill), or doc comments (→ See `samber/cc-skills-golang@golang-documentation` skill).

golang-concurrencySkill

Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singleflight, worker pools, or fan-out/fan-in pipelines. Also triggers when you detect goroutine leaks, race conditions, channel ownership issues, or need to choose between channels and mutexes.

golang-contextSkill

Idiomatic context.Context usage in Golang — propagation through API boundaries, cancellation, timeouts and deadlines, request-scoped values, context.WithoutCancel for background work outliving requests. Apply when designing context propagation across layers, debugging leaked or unexpired contexts, choosing between context.Background/TODO/WithoutCancel, or storing values in context. Not for code that merely accepts ctx as first parameter.

golang-continuous-integrationSkill

CI/CD pipeline configuration using GitHub Actions for Golang projects — testing, linting, SAST, security scanning, code coverage, Dependabot, Renovate, GoReleaser, code review automation, and release pipelines. Use when setting up or improving Go project CI, configuring GitHub Actions workflows, adding linters or security scanners, automating dependency updates, or adding quality gates.

golang-data-structuresSkill

Golang data structures — slices (internals, capacity growth, preallocation, slices package), maps (internals, hash buckets, maps package), arrays, container/list/heap/ring, strings.Builder vs bytes.Buffer, generic collections, pointers (unsafe.Pointer, weak.Pointer), and copy semantics. Use when choosing or optimizing Go data structures, implementing generic containers, using container/ packages, unsafe or weak pointers, or questioning slice/map internals.

golang-databaseSkill

Comprehensive guide for Go database access — parameterized queries, struct scanning, NULLable columns, transactions, isolation levels, SELECT FOR UPDATE, connection pool, batch processing, context propagation, and migration tooling. Use when writing, reviewing, or debugging Golang code that interacts with PostgreSQL, MariaDB, MySQL, or SQLite; for database testing; or for questions about database/sql, sqlx, or pgx. Does NOT generate database schemas or migration SQL.