4.5 KiB
Advanced — uber-go/dig
Detail topics that are referenced from SKILL.md. Each section is self-contained.
Decorate
Decorate modifies a value already provided in the container — the decorator receives the original instance and returns a replacement. Common uses: enriching a logger with context, wrapping a metrics scope with tags, swapping a real client for a recording one in a child scope.
c.Decorate(func(log *zap.Logger) *zap.Logger {
return log.Named("worker")
})
Decorators apply to the scope they were registered in and to that scope's descendants. Use them at scope boundaries or package wiring boundaries, not in main(), so changes stay local.
Scopes
A Scope is a child container that inherits providers from its parent and can add or override its own. Scopes let request-, tenant-, or module-level dependencies coexist with shared singletons:
root := dig.New()
root.Provide(NewLogger)
root.Provide(NewDatabase)
requestScope := root.Scope("request")
requestScope.Provide(NewRequestContext) // only visible inside requestScope
requestScope.Decorate(func(l *zap.Logger) *zap.Logger {
return l.With(zap.String("scope", "request"))
})
By default, providers registered to a scope are private to that scope and its children. Pass dig.Export(true) to Provide inside a scope to make the type visible from the parent:
requestScope.Provide(NewSharedCache, dig.Export(true))
Optional Dependencies
optional:"true" lets a consumer compile and run when a provider is missing. Use it sparingly — optional dependencies hide configuration mistakes. They make sense for genuinely optional features (a tracing exporter, an in-memory cache) but not for core services like a database.
type Params struct {
dig.In
Logger *zap.Logger
Tracer trace.Tracer `optional:"true"`
}
Error Handling
dig wraps the constructor error with the dependency path so you can see which graph edge failed:
if err := c.Invoke(run); err != nil {
// err describes the chain: "could not build *http.Server: ..."
}
Useful helpers:
errors.As(err, &dig.Error{})— true if the error originated inside digdig.RootCause(err)— unwrap to the original constructor error returned by user codedig.IsCycleDetected(err)— true if the graph contains a cycle (typically reported at firstInvokeunlessDeferAcyclicVerificationis set)errors.As(err, &dig.PanicError{})— whenRecoverFromPanicsis enabled, a panicking constructor surfaces as this typed error
Visualization
dig can emit the dependency graph in DOT format — useful when wiring becomes too tangled to reason about by reading code:
f, _ := os.Create("graph.dot")
_ = dig.Visualize(c, f)
// then: dot -Tpng graph.dot -o graph.png
dig.VisualizeError(err) highlights the failed edges when an Invoke returns an error — invaluable for debugging "missing type" failures in deep graphs.
Quick Reference
Container
| Function/Method | Purpose |
|---|---|
dig.New(opts...) |
Create a root container |
c.Provide(ctor, opts...) |
Register a constructor |
c.Invoke(fn, opts...) |
Run a function with injected dependencies |
c.Decorate(fn, opts...) |
Modify a previously-provided value within a scope |
c.Scope(name, opts...) |
Create a child scope (private providers by default) |
c.String() |
Human-readable text summary of providers (not DOT; use dig.Visualize for DOT) |
Provide options
| Option | Purpose |
|---|---|
dig.Name("...") |
Disambiguate same-typed providers |
dig.Group("...") |
Add the result to a value group |
dig.As(new(I)) |
Provide the concrete value as one or more interfaces |
dig.Export(true) |
Make a scope-level provider visible from the root |
dig.FillProvideInfo(&info) |
Capture metadata for tooling |
Container options
| Option | Purpose |
|---|---|
dig.DeferAcyclicVerification() |
Defer cycle check to first Invoke |
dig.RecoverFromPanics() |
Convert constructor panics into dig.PanicError |
dig.DryRun(true) |
Validate without invoking constructors |
Errors
| Helper | Purpose |
|---|---|
dig.RootCause(err) |
Unwrap to the user-returned error |
dig.IsCycleDetected(err) |
True if the graph has a cycle |
errors.As(err, &dig.PanicError{}) |
Detect a recovered panic |
dig.Visualize(c, w, opts...) |
Write the graph in DOT format |