Go DI has always been a trade-off.
Runtime DI frameworks provide a convenient API, but they rely on reflection and discover dependency problems during application startup.
Compile-time DI frameworks avoid those problems, but some APIs become verbose and less ergonomic.
I have been exploring a different approach:
dig — compile-time dependency injection for Go with an Fx-style API and Wire-style code generation.
Repository:
https://github.com/shanjunmei/dig
The main design goals are:
-
dependency graph resolution during
go generate -
zero runtime reflection
-
zero runtime dependency after code generation
-
generated code is plain Go
-
minimal API:
Build,Provide,Supply,Invoke,Module
Example:
func InitApp() func(context.Context) error {
return dig.Build(
dig.Provide(NewConfig),
dig.Provide(NewDatabase),
dig.Invoke(StartServer),
)
}
After generation, the application does not depend on a DI runtime.
Some design questions I would like feedback on:
-
Do you prefer compile-time DI or runtime DI in large Go projects?
-
Is avoiding reflection an important advantage in practice?
-
Are there DI patterns from Wire/Fx/custom solutions that should be preserved?
-
What API choices would make a Go DI library feel natural?
The goal is not to create another DI library for its own sake, but to explore what a more Go-like DI design could look like.
Feedback and criticism are welcome.