[Open Source] dig: Compile-Time DI for Go — Combine Wire’s Zero Overhead with Fx’s Clean DX

After years of building large-scale Go projects, I’ve always believed that Go engineering optimization should be evolution with no tradeoffs, not compromise.

Dependency Injection is a foundational piece for medium/large Go systems, monorepos and microservices. However, the two mainstream Go DI solutions both have fatal flaws that force developers into an awkward dilemma:

:high_voltage: Uber Fx: Great DX, terrible runtime overhead

  • Clean, elegant API and excellent modular design
  • Runtime reflection heavy: slow startup, non-trivial runtime overhead, larger binary size
  • All dependency errors (missing providers, circular dependencies, type mismatch) only panic at runtime, not compile time
  • Too risky for high-performance infrastructure and core online services

:brick: Google Wire: Perfect performance, terrible developer experience

  • 100% compile-time code generation, zero reflection, zero runtime dependency
  • Guaranteed compile-time safety, fully aligned with Go’s static philosophy
  • Verbose, counter-intuitive API, mandatory wire.NewSet boilerplate
  • Only supports constant injection, no runtime variable supply
  • Flat module structure only, no nested modularity for large projects
  • Unreadable error logs, extremely painful dependency troubleshooting

For a long time, Go developers had to choose: either good DX with performance risk, or perfect performance with poor productivity.

So I built dig — a pure Go compile-time DI library that eliminates all tradeoffs.

:sparkles: dig Core Positioning

dig = Wire’s compile-time safety & zero overhead + Fx’s elegant API & modularity + exclusive safety checks

It abides strictly by Go’s design philosophy: simple, transparent, predictable, no magic.

  • All dependency graph parsing, circular detection and unused component validation happen at compile-time (go generate)
  • Outputs pure handwritten-style Go code, zero runtime reflection, zero framework dependency
  • Final binary performance is identical to manual initialization

:rocket: Why dig Is Better Than Existing DI Tools

1. Fx-style Minimal & Intuitive API

Only 5 core APIs, near-zero learning curve, completely gets rid of Wire’s verbose boilerplate:

  • Provide: Register constructor functions
  • Supply: Inject any value (constants, global variables, runtime values — Wire’s biggest limitation fixed)
  • Invoke: Execute startup hooks after all dependencies are ready
  • Module: Nested modular combination for monorepo architecture
  • Build: Assemble the full dependency graph

Minimal usage example:

//go:build digen
func InitApp() func(context.Context) error {
    return dig.Build(
        dig.Provide(NewConfig),
        dig.Provide(NewDB),
        dig.Supply(DefaultTimeout),
        dig.Invoke(func(srv *Server) error { return srv.Run() }),
    )
}

2. Exclusive Closure Safety Check (Unique to dig)

Both Fx and Wire suffer from implicit closure capture bugs, which cause intermittent runtime panics that are extremely hard to reproduce.

dig enforces compile-time closure validation: it prohibits capturing local function variables in builder functions, only allowing package-level variables and literals. This eliminates implicit dependency bugs at the syntax level.

3. Complete Observability & Refined Strategy

  • Compile-time: 3-level unused component strategy (error/ignore/drop), automatic dead code cleanup
  • Runtime: Plugable global logging interface, natively compatible with zap/logrus
  • Error prompt: Hierarchical dependency chain logs, precise positioning without obscure stack traces

4. Modern Go Feature Support

  • Native generic constructor & generic injection support
  • Nested module management for large monorepo projects
  • Mixed compile-tag selection and runtime conditional injection
  • Built-in wrapper type resolution to avoid identical type conflicts

:bar_chart: Feature Comparison: dig vs Wire vs Fx

Capability dig Google Wire Uber Fx
Compile-time code generation :white_check_mark: :white_check_mark: :cross_mark: Runtime reflection
Zero runtime reflection :white_check_mark: :white_check_mark: :cross_mark:
Zero runtime framework dependency :white_check_mark: :white_check_mark: :cross_mark:
Compile-time error capture :white_check_mark: :white_check_mark: :cross_mark: Panic on startup
Clean Fx-style API :white_check_mark: :cross_mark: Verbose boilerplate :white_check_mark:
Closure safety validation :white_check_mark: Exclusive :cross_mark: No check :cross_mark: No check
Arbitrary runtime value injection :white_check_mark: :cross_mark: Const only :white_check_mark:
Unused component optimization :white_check_mark: 3-level strategy :cross_mark: Only delete :cross_mark: Not supported

:light_bulb: Philosophy: What Go DI Should Really Be

Most Go developers resist DI not because DI is unnecessary, but because they reject Java-style heavy, black-box framework magic.

  • Fx breaks predictability: runtime reflection brings uncontrollable runtime uncertainty.
  • Wire breaks simplicity: rigid syntax damages development efficiency for large projects.

dig’s goal is simple: no more tradeoffs.

It keeps Go’s original simplicity and transparency, while solving the chaos of manual initialization in multi-layer, multi-module projects:

  • No global variable flooding
  • No scattered initialization logic
  • No chain reaction modification risks
  • Full mock capability for unit testing

:package: Installation & Quick Start

Current version: v1.0.10 (Go 1.21+, MIT license, free for commercial use)

go get github.com/shanjunmei/dig@v1.0.10
go install github.com/shanjunmei/dig/cmd/digen@latest

GitHub: GitHub - shanjunmei/dig: dig is a compile‑time code generation based DI tool for Go. It provides a more intuitive API than Wire , with native generics support , built‑in closure capture safety that Wire lacks, and is faster than Fx by eliminating runtime reflection — all with zero runtime dependencies · GitHub

Full documentation, complete examples and migration guides are available in the repo.

:handshake: Welcome Feedback & Contribution

dig is built to fill the last gap of Go’s DI ecosystem. If you are tired of Fx’s runtime overhead and Wire’s cumbersome syntax, give dig a try.

Stars, issues and PRs are all welcome! Let’s build a more native, efficient and developer-friendly DI solution for Go.

1 Like