Generated banner for Golang Google Wire
Generated logo for Golang Google Wire

Golang Google Wire

Samuel BertheCommunityCreated by samberDistributed by Samuel Berthe

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Compile-time dependency injection in Golang using google/wire — wire.NewSet, wire.Build, wire.Bind (interface→concrete), wire.Struct, wire.Value, wire.InterfaceValue, wire.FieldsOf, cleanup functions, //go:build wireinject injector files, and generated wire_gen.go. Apply when using or adopting google/wire, when the codebase imports `github.com/google/wire`, or when wiring an application graph at compile time via `wire.Build`. For runtime DI with reflection, see `samber/cc-skills-golang@golang-uber-dig` skill.
— the description by samber

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

google/wire is a code-generation toolkit for dependency injection in Go. Unlike runtime containers that use reflection, wire resolves the dependency graph at compile time and generates plain Go code. This approach ensures that missing dependencies or configuration errors are caught during the build process rather than at runtime. The workflow involves defining provider functions and injector stubs, then running the wire command to generate the final initialization code.

What it does

  • Resolves complex dependency graphs at compile time
  • Generates plain Go constructor code without reflection
  • Supports interface binding and struct field injection
  • Manages cleanup functions in reverse construction order
  • Enforces strict type safety for dependency resolution

When to use it

  • When you want to avoid runtime reflection for dependency injection
  • When you need to catch dependency errors during compilation
  • When building Go applications with complex object graphs
  • When you prefer explicit, generated code over magic runtime containers

Advantages

  • Zero runtime overhead
  • Early error detection during build
  • No magic or hidden runtime behavior
  • Easy to debug as generated code is standard Go
  • Supports complex cleanup chains automatically

Usage examples

“Generate the dependency graph for my application.”
The agent runs 'wire ./...' to process injector files and generate the 'wire_gen.go' file containing the necessary constructor calls.
“How do I bind an interface to a concrete implementation in wire?”
The agent provides a 'wire.Bind' example, showing how to map an interface type to a concrete struct provider within a 'wire.NewSet'.
“My application has a cleanup function for the database connection.”
The agent explains how to return a cleanup function from the provider and how wire automatically chains it in reverse order for safe shutdown.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/samber/golang-google-wire/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip golang-google-wire.zip -d .agents/skills

Documentation by samber

Persona: You are a Go architect using wire for compile-time DI. You let the compiler catch missing dependencies, treat wire_gen.go as committed source, and re-run wire ./... after every graph change.

Dependencies:

  • wire: go install github.com/google/wire/cmd/wire@latest

Using google/wire for Compile-Time Dependency Injection in Go

Code-generation DI toolkit. Wire resolves the dependency graph at compile time and emits plain Go constructor calls — no runtime container, no reflection. Errors appear when you run wire ./..., not at first request.

Note: google/wire was archived in August 2025 (feature-complete; bug fixes still accepted).

Official Resources: pkg.go.dev · github.com/google/wire · User Guide · Best Practices

This skill is not exhaustive — 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), preferred 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.

go get -tool github.com/google/wire/cmd/wire@latest
go get github.com/google/wire

wire vs. Runtime DI

Concernwiredig / fx / samber/do
ResolutionCompile time (codegen)Runtime (reflection)
Error detectionwire ./... failsFirst Invoke/startup
Runtime containerNone — plain Go callsPresent
Lifecycle hooksNot built infx: OnStart/OnStop
Generated fileswire_gen.go (committed)None

For lifecycle, lazy loading, and a full matrix see samber/cc-skills-golang@golang-dependency-injection.

Providers

A provider is any Go function — inputs are dependencies, outputs are provided types. Three return forms:

func NewConfig() *Config                          { return &Config{Addr: ":8080"} }
func NewDB(cfg *Config) (*sql.DB, error)          { return sql.Open("postgres", cfg.DSN) }
func NewRedis(cfg *Config) (*redis.Client, func(), error) { // cleanup chained in reverse order
    c := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr})
    return c, func() { c.Close() }, nil
}

Provider Sets

wire.NewSet groups providers for reuse. Sets can reference other sets.

// infra/wire.go
var InfraSet = wire.NewSet(
    NewConfig,
    NewDB,
    NewRedis,
)

// service/wire.go
var ServiceSet = wire.NewSet(
    NewUserRepo,
    NewUserService,
    wire.Bind(new(UserStore), new(*UserRepo)), // interface binding
)

Keep sets small: library sets expose a stable surface (adding inputs or removing outputs breaks downstream injectors). One set per package is a useful default.

Injectors and //go:build wireinject

The injector file declares the initialization function. Wire generates its body into wire_gen.go and replaces the stub.

//go:build wireinject

package main

import "github.com/google/wire"

// Wire generates the body of this function.
func InitApp() (*App, func(), error) {
    wire.Build(InfraSet, ServiceSet, NewApp)
    return nil, nil, nil // replaced by codegen
}

The //go:build wireinject tag prevents the stub from being compiled into the binary — only wire_gen.go (which has no such tag) makes it through go build. Without this tag, both files define the same function, causing a compile error.

Alternative syntax when a dummy return is inconvenient:

func InitApp() (*App, func(), error) {
    panic(wire.Build(InfraSet, ServiceSet, NewApp))
}

Interface Bindings

Wire forbids implicit interface satisfaction — you must declare bindings explicitly so the graph is unambiguous when multiple types implement the same interface.

var Set = wire.NewSet(
    NewPostgresUserRepo,
    wire.Bind(new(UserStore), new(*PostgresUserRepo)), // tell wire: *PostgresUserRepo satisfies UserStore
)

Explicit bindings prevent graph breakage when a new type implementing the same interface is added elsewhere.

Struct Providers and Values

wire.Struct fills struct fields from the graph without a manual constructor. Tag fields wire:"-" to exclude them.

wire.Struct(new(Server), "Logger", "DB") // inject named fields
wire.Struct(new(Server), "*")            // inject all non-excluded fields
wire.Value(Foo{X: 42})                   // constant expression (no fn calls / channels)
wire.InterfaceValue(new(io.Reader), os.Stdin) // interface-typed literal
wire.FieldsOf(new(Config), "DSN", "Addr")    // promote struct fields as graph nodes

See advanced.md for the wire:"-" exclusion tag and wire.FieldsOf details.

Disambiguating Duplicate Types

Wire forbids two providers for the same type. Wrap the underlying type in distinct named types so each has exactly one provider:

type PrimaryDSN string
type ReplicaDSN string

Full Application Example

// wire.go — injector, excluded from binary via build tag
//go:build wireinject

package main

func InitApp() (*App, func(), error) {
    wire.Build(config.ConfigSet, infra.InfraSet, service.ServiceSet, NewApp)
    return nil, nil, nil
}

// main.go
func main() {
    app, cleanup, err := InitApp()
    if err != nil { log.Fatal(err) }
    defer cleanup()
    app.Run()
}

Wire generates wire_gen.go (plain Go, committed, DO NOT EDIT). For a full example with per-package sets, cleanup-heavy graphs, and generated output, see recipes.md.

Codegen Workflow

wire ./...           # regenerate all injectors in the module
wire check ./...     # validate graph without regenerating (fast CI check)

Run wire ./... after every constructor signature change. Add //go:generate go run github.com/google/wire/cmd/wire to injector files so go generate ./... also works. Commit wire_gen.go — it must stay in sync for CI builds.

Best Practices

  1. Never edit wire_gen.go — it is overwritten on every wire ./... run. Treat it as a build artifact that happens to be committed; source of truth is the provider and injector files.

  2. Always add //go:build wireinject to injector files — omitting it causes duplicate-symbol compile errors because both the stub and the generated file define the same function.

  3. Use named types to distinguish values of the same underlying type — wire enforces one provider per type; named types like type DSN string let you have PrimaryDSN and ReplicaDSN coexist.

  4. Keep library provider sets minimal and backward-compatible — adding new required inputs breaks downstream injectors; removing outputs does too. Introduce only newly-created types in the same release.

  5. Return (T, func(), error) from cleanup providers and let wire chain them — wire generates the correct reverse-order cleanup and handles partial failures (if construction fails midway, only already-built cleanups run).

  6. Keep injector files focused — one function per file, one package import at a time. Fat injectors with dozens of wire.Build arguments are hard to reason about; delegate to per-package sets.

Common Mistakes

MistakeFix
Editing wire_gen.go manuallyNever edit it. Change providers or injectors and re-run wire ./....
Missing //go:build wireinjectAdd the tag as the very first line of every injector file.
Two providers returning *sql.DBWrap with a named struct type: type PrimaryDB struct { *sql.DB } — Wire does not distinguish pointer type aliases.
Injecting an interface without wire.BindAdd wire.Bind(new(MyInterface), new(*MyImpl)) to the provider set.
Forgetting to re-run wire ./... after changesRun wire before go build; add it to go generate or a Makefile target.
Calling cleanup() without guarding for nilWire returns nil cleanup on construction error; guard with if cleanup != nil { defer cleanup() }.

Testing

Wire generates plain Go constructors, so unit tests use manual injection — no container to clone or reset. For testing patterns (test injectors swapping real providers for fakes, CI stale-check for wire_gen.go), see testing.md.

Further Reading

  • advanced.md — cleanup chains, multiple injectors, set nesting, error catalogue, codegen flags, quick reference

  • recipes.md — HTTP server, multi-injector build, cleanup-heavy graph, CLI embedding

  • testing.md — test injectors, fake bindings, CI stale check

Cross-References

  • → See samber/cc-skills-golang@golang-dependency-injection skill for DI concepts and library comparison

  • → See samber/cc-skills-golang@golang-uber-dig skill for runtime reflection-based DI without lifecycle

  • → See samber/cc-skills-golang@golang-uber-fx skill for runtime DI with lifecycle hooks, modules, and signal-aware Run()

  • → See samber/cc-skills-golang@golang-samber-do skill for generics-based DI without reflection

  • → See samber/cc-skills-golang@golang-structs-interfaces skill for interface design patterns

  • → See samber/cc-skills-golang@golang-testing skill for general testing patterns

If you encounter a bug or unexpected behavior in google/wire, open an issue at https://github.com/google/wire/issues.

Files

references/advanced.md

Advanced — google/wire

Detail topics referenced from SKILL.md. Each section is self-contained.

Table of Contents

  • Cleanup Chains

  • Multiple Injectors in One Package

  • wire.NewSet Nesting Strategies

  • wire:"-" Exclusion Tag

  • Common Codegen Errors

  • Codegen Flags

  • panic(wire.Build(...)) Alternate Syntax

  • Accepting External Values as Injector Arguments

  • Quick Reference

Cleanup Chains

When a provider returns (T, func(), error), Wire adds the cleanup to a chain. The generated injector runs cleanups in reverse construction order: the last-built dependant is cleaned up first, ensuring dependants are torn down before their dependencies.

// Provider with cleanup
func NewDB(cfg *Config) (*sql.DB, func(), error) {
    db, err := sql.Open("postgres", string(cfg.DSN))
    if err != nil { return nil, nil, err }
    return db, func() { db.Close() }, nil
}

func NewCache(cfg *Config) (*redis.Client, func(), error) {
    c := redis.NewClient(&redis.Options{Addr: cfg.CacheAddr})
    return c, func() { c.Close() }, nil
}

Wire generates something like:

func InitApp() (*App, func(), error) {
    cfg := NewConfig()
    db, dbCleanup, err := NewDB(cfg)
    if err != nil { return nil, nil, err }
    cache, cacheCleanup, err := NewCache(cfg)
    if err != nil {
        dbCleanup()  // already-built cleanups run on partial failure
        return nil, nil, err
    }
    app := NewApp(db, cache)
    return app, func() {
        cacheCleanup()  // reverse order
        dbCleanup()
    }, nil
}

Caller pattern — guard against nil cleanup on construction failure:

app, cleanup, err := InitApp()
if err != nil { log.Fatal(err) }
defer cleanup()

Wire always returns a non-nil cleanup function when construction succeeds. If construction fails midway, the returned cleanup is nil — guard before calling.

Multiple Injectors in One Package

A package can contain multiple injector functions. Each must live in a file with //go:build wireinject. All generated functions land in wire_gen.go in the same package.

//go:build wireinject

package main

// Production injector
func InitProdApp() (*App, func(), error) {
    wire.Build(ProdSet, NewApp)
    return nil, nil, nil
}

// Development injector with debug providers
func InitDevApp() (*App, func(), error) {
    wire.Build(DevSet, NewApp)
    return nil, nil, nil
}

Select at runtime with a flag, or at build time with separate //go:build prod / //go:build !prod constraints on the injector files.

wire.NewSet Nesting Strategies

Sets can contain other sets, building a hierarchy that mirrors your package structure.

// pkg/config/wire.go
var ConfigSet = wire.NewSet(NewConfig)

// pkg/infra/wire.go
var InfraSet = wire.NewSet(
    config.ConfigSet, // embed upstream set
    NewDB,
    NewCache,
)

// pkg/service/wire.go
var ServiceSet = wire.NewSet(
    NewUserService,
    wire.Bind(new(UserStore), new(*UserRepo)),
)

// wire.go (injector)
wire.Build(infra.InfraSet, service.ServiceSet, NewApp)

Library set stability rules (from upstream best practices):

  • Safe: replace one provider with another that has the same or fewer inputs, in the same release.

  • Safe: introduce a brand-new output type not previously provided.

  • Breaking: add a new required input to a provider — downstream injectors cannot satisfy it.

  • Breaking: remove a provided output type — downstream injectors that depend on it fail.

  • Breaking: add a type that the injector already provides — Wire reports a duplicate.

wire:"-" Exclusion Tag

Exclude a struct field from wire.Struct injection by tagging it:

type Server struct {
    Logger  *zap.Logger
    DB      *sql.DB
    mu      sync.Mutex   `wire:"-"` // unexported — auto-excluded
    Timeout time.Duration `wire:"-"` // exported but opt-out
}

wire.Struct(new(Server), "*") // injects Logger and DB; skips mu and Timeout

Unexported fields are always skipped regardless of the tag.

Common Codegen Errors

Error messageRoot causeFix
no provider found for TYPEA dependency is not provided by any set in wire.BuildAdd the missing provider or set
multiple bindings for TYPETwo providers return the same typeUse named types or remove the duplicate
argument N has no provider for TYPEAn interface is requested but no wire.Bind maps to itAdd wire.Bind(new(Iface), new(*Impl)) to a set
cycle detectedA → B → A circular dependencyBreak the cycle by introducing an interface or factory
wire.Build used outside of injector functionwire.Build called from a non-injector functionOnly call wire.Build inside functions with the build tag
duplicate symbol / redeclared in this blockInjector file is missing //go:build wireinjectAdd the build tag as the first line

Codegen Flags

# Specify output file prefix (default: wire_gen)
wire -output_file_prefix=init gen ./cmd/server

# Apply build tags during generation
wire -tags=integration gen ./...

# Prepend a header file (e.g., license comment) to generated output
wire -header_file=hack/boilerplate.go.txt gen ./...

panic(wire.Build(...)) Alternate Syntax

Wire accepts either a dummy return or a panic call as the injector body. The panic form avoids writing zero-value returns for complex types:

// Preferred when return types are complex or error-prone to zero-initialize
func InitApp(ctx context.Context) (*App, func(), error) {
    panic(wire.Build(AppSet))
}

Wire detects both forms and replaces the body during codegen. The panic is never reached in the compiled binary — only the generated wire_gen.go version is compiled.

Accepting External Values as Injector Arguments

When a value is constructed before wire runs (e.g., parsed flags, an http.Client from a test), pass it as a parameter to the injector rather than providing it from within the graph:

//go:build wireinject

func InitApp(cfg *Config) (*App, func(), error) {
    wire.Build(InfraSet, ServiceSet, NewApp)
    return nil, nil, nil
}

// main.go
cfg := parseFlags()
app, cleanup, err := InitApp(cfg)

Wire treats injector parameters as pre-built providers — they satisfy dependencies without needing a wire.NewSet entry.

Quick Reference

SymbolPurpose
wire.NewSet(providers...)Group providers into a reusable set
wire.Build(sets...)Declare injector body (codegen replaces it)
wire.Bind(new(Iface), new(*Concrete))Bind interface to concrete type
wire.Struct(new(T), "Field", ...)Inject struct fields from the graph
wire.Struct(new(T), "*")Inject all non-excluded fields
wire.Value(expr)Bind a constant expression (no fn calls/channels)
wire.InterfaceValue(new(I), value)Bind a value to an interface type
wire.FieldsOf(new(T), "Field", ...)Promote struct fields as individual graph nodes
//go:build wireinjectBuild tag: exclude injector stub from binary
wire_gen.goGenerated output — commit, never edit
wire ./...Regenerate all injectors in the module
wire check ./...Validate graph without regenerating

Requirements and compatibility

Written for: Claude Code, OpenAI Codex

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Claude Code frontmatter

The author says: Designed for Claude Code, Codex or similar harness, and for projects using Golang.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
samber
Publisher
Samuel Berthe (Community)
Distributed by
Samuel Berthe
Source
samber/cc-skills-golang · skills/golang-google-wire · commit bb1d43d
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by samber or Samuel Berthe.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download golang-google-wire.zip