https://github.com/junioryono/godi
Dependency Injection with Service Lifetimes for Go
https://github.com/junioryono/godi
Last synced: about 2 months ago
JSON representation
Dependency Injection with Service Lifetimes for Go
- Host: GitHub
- URL: https://github.com/junioryono/godi
- Owner: junioryono
- License: mit
- Created: 2025-07-10T01:30:28.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-12-14T16:36:22.000Z (3 months ago)
- Last Synced: 2025-12-16T10:30:29.849Z (3 months ago)
- Language: Go
- Homepage: https://godi.readthedocs.io/en/latest/
- Size: 995 KB
- Stars: 62
- Watchers: 2
- Forks: 1
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: CODEOWNERS
Awesome Lists containing this project
- fucking-awesome-go - godi - Microsoft-style dependency injection for Go with scoped lifetimes and generics. (Miscellaneous / Dependency Injection)
- awesome-go - junioryono/godi
- awesome-go-with-stars - godi - style dependency injection for Go with scoped lifetimes and generics. | 2026-03-01 | (Microsoft Office / Dependency Injection)
- awesome-go-cn - godi - style dependency injection for Go with scoped lifetimes and generics. [![godoc][D]](https://godoc.org/github.com/junioryono/godi) (杂项 / 依赖注入)
- awesome-go - godi - Microsoft-style dependency injection for Go with scoped lifetimes and generics. (Miscellaneous / Dependency Injection)
- awesome-go - godi - Microsoft-style dependency injection for Go with scoped lifetimes and generics. (Miscellaneous / Dependency Injection)
README
# godi
[](https://pkg.go.dev/github.com/junioryono/godi/v4)
[](https://goreportcard.com/report/github.com/junioryono/godi)
[](https://github.com/junioryono/godi/actions/workflows/test.yml)
[](https://codecov.io/gh/junioryono/godi)
[](LICENSE)
**Dependency injection for Go with service lifetimes.** godi automatically wires your application, manages service lifetimes, and handles cleanup - so you can focus on business logic.
```go
services := godi.NewCollection()
services.AddSingleton(NewDatabase) // One instance, shared everywhere
services.AddScoped(NewUserService) // One instance per request
services.AddTransient(NewEmailBuilder) // New instance every time
provider, _ := services.Build()
user := godi.MustResolve[*UserService](provider)
```
## Why godi?
**The problem:** As applications grow, manually wiring dependencies becomes painful. Constructor parameters multiply, initialization order matters, and per-request isolation requires careful scope management.
```go
// Manual wiring - gets messy fast
config := NewConfig()
logger := NewLogger(config)
db := NewDatabase(config, logger)
cache := NewCache(config, logger)
userRepo := NewUserRepository(db, cache, logger)
orderRepo := NewOrderRepository(db, cache, logger)
userService := NewUserService(userRepo, logger)
orderService := NewOrderService(orderRepo, userService, logger)
// ... 20 more lines
```
**The solution:** Register constructors. godi figures out the rest.
```go
// godi - register in any order, resolve anything
services := godi.NewCollection()
services.AddSingleton(NewConfig)
services.AddSingleton(NewLogger)
services.AddSingleton(NewDatabase)
services.AddScoped(NewUserService)
// ... godi handles the wiring
```
## Installation
```bash
go get github.com/junioryono/godi/v4
```
Requires **Go 1.21+**. Zero external dependencies.
## Quick Start
```go
package main
import (
"fmt"
"github.com/junioryono/godi/v4"
)
type Logger struct{}
func (l *Logger) Log(msg string) { fmt.Println(msg) }
func NewLogger() *Logger { return &Logger{} }
type UserService struct {
logger *Logger
}
func NewUserService(logger *Logger) *UserService {
return &UserService{logger: logger}
}
func (s *UserService) Greet() { s.logger.Log("Hello from UserService!") }
func main() {
// 1. Register services
services := godi.NewCollection()
services.AddSingleton(NewLogger)
services.AddSingleton(NewUserService)
// 2. Build the container
provider, _ := services.Build()
defer provider.Close()
// 3. Resolve and use - dependencies wired automatically
users := godi.MustResolve[*UserService](provider)
users.Greet() // Hello from UserService!
}
```
## Service Lifetimes
godi provides three lifetimes to control when instances are created:
```
┌──────────────────────────────────────────────────────────────────┐
│ Application │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ SINGLETON: Database, Logger, Config │ │
│ │ Created once, shared everywhere │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Request 1 │ │ Request 2 │ │ Request 3 │ │
│ │ SCOPED: │ │ SCOPED: │ │ SCOPED: │ │
│ │ Transaction │ │ Transaction │ │ Transaction │ │
│ │ UserSession │ │ UserSession │ │ UserSession │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
| Lifetime | Created | Shared | Use Case |
| ----------- | -------------- | ------------ | ----------------------------- |
| `Singleton` | Once | App-wide | Database pools, config |
| `Scoped` | Once per scope | Within scope | Request context, transactions |
| `Transient` | Every time | Never | Builders, temp objects |
```go
services.AddSingleton(NewDatabasePool) // One pool for the whole app
services.AddScoped(NewTransaction) // Fresh transaction per request
services.AddTransient(NewQueryBuilder) // New builder every resolution
```
## HTTP Integration
godi shines in web applications where each request needs isolated services:
```go
package main
import (
"net/http"
"github.com/junioryono/godi/v4"
godihttp "github.com/junioryono/godi/v4/http"
)
type UserController struct {
// Dependencies injected automatically
}
func (c *UserController) List(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`["alice", "bob"]`))
}
func main() {
services := godi.NewCollection()
services.AddSingleton(NewLogger)
services.AddScoped(NewUserController)
provider, _ := services.Build()
defer provider.Close()
mux := http.NewServeMux()
mux.HandleFunc("GET /users", godihttp.Handle((*UserController).List))
// ScopeMiddleware creates a fresh scope per request
handler := godihttp.ScopeMiddleware(provider)(mux)
http.ListenAndServe(":8080", handler)
}
```
### Framework Support
| Framework | Package | Install |
| --------- | ------------------------------------- | -------------------------------------------- |
| net/http | `github.com/junioryono/godi/v4/http` | `go get github.com/junioryono/godi/v4/http` |
| Gin | `github.com/junioryono/godi/v4/gin` | `go get github.com/junioryono/godi/v4/gin` |
| Chi | `github.com/junioryono/godi/v4/chi` | `go get github.com/junioryono/godi/v4/chi` |
| Echo | `github.com/junioryono/godi/v4/echo` | `go get github.com/junioryono/godi/v4/echo` |
| Fiber | `github.com/junioryono/godi/v4/fiber` | `go get github.com/junioryono/godi/v4/fiber` |
## Features
### Interface Binding
Register concrete types as interfaces for easy testing and swapping:
```go
services.AddSingleton(NewConsoleLogger, godi.As[Logger]())
// Resolve by interface
logger := godi.MustResolve[Logger](provider)
```
### Keyed Services
Multiple implementations of the same type:
```go
services.AddSingleton(NewPrimaryDB, godi.Name("primary"))
services.AddSingleton(NewReplicaDB, godi.Name("replica"))
primary := godi.MustResolveKeyed[Database](provider, "primary")
replica := godi.MustResolveKeyed[Database](provider, "replica")
```
### Service Groups
Collect related services for batch operations:
```go
services.AddSingleton(NewEmailValidator, godi.Group("validators"))
services.AddSingleton(NewPhoneValidator, godi.Group("validators"))
validators := godi.MustResolveGroup[Validator](provider, "validators")
for _, v := range validators {
v.Validate(input)
}
```
### Parameter Objects
Simplify constructors with many dependencies:
```go
type ServiceParams struct {
godi.In
DB Database
Cache Cache
Logger Logger
Metrics Metrics `optional:"true"`
}
func NewService(params ServiceParams) *Service {
return &Service{db: params.DB, cache: params.Cache}
}
```
### Result Objects
Register multiple services from one constructor:
```go
type InfraResult struct {
godi.Out
DB *Database
Cache *Cache
Health *HealthChecker
}
func NewInfra(cfg *Config) InfraResult {
db := connectDB(cfg)
return InfraResult{
DB: db,
Cache: NewCache(cfg),
Health: NewHealthChecker(db),
}
}
// One registration, three services
services.AddSingleton(NewInfra)
```
### Modules
Organize large applications:
```go
// users/module.go
var Module = godi.NewModule("users",
godi.AddScoped(NewUserRepository),
godi.AddScoped(NewUserService),
)
// main.go
services.AddModules(
infrastructure.Module,
users.Module,
orders.Module,
)
```
### Automatic Cleanup
Services implementing `Close() error` are cleaned up automatically:
```go
func (d *Database) Close() error {
return d.conn.Close()
}
provider.Close() // Database.Close() called automatically
```
## Error Handling
godi validates at build time to catch problems early:
```go
provider, err := services.Build()
if err != nil {
// Circular dependency? Missing service? Lifetime conflict?
// The error message tells you exactly what's wrong
log.Fatal(err)
}
```
Common errors caught at build time:
- **Circular dependencies** - `*A -> *B -> *A`
- **Missing dependencies** - `*UserService requires *Database (not registered)`
- **Lifetime conflicts** - `singleton *Cache cannot depend on scoped *RequestContext`
## Testing
Replace implementations for testing:
```go
func TestUserService(t *testing.T) {
services := godi.NewCollection()
services.AddSingleton(func() Database { return &MockDB{} })
services.AddScoped(NewUserService)
provider, _ := services.Build()
defer provider.Close()
scope, _ := provider.CreateScope(context.Background())
defer scope.Close()
svc := godi.MustResolve[*UserService](scope)
// Test with mock database
}
```
## Comparison
| Feature | godi | Wire | Fx | do |
| -------------------------- | ---- | ---- | --- | --- |
| No code generation | Yes | No | Yes | Yes |
| Service lifetimes | Yes | No | No | No |
| Scoped services | Yes | No | No | No |
| Build-time validation | Yes | Yes | No | No |
| HTTP framework integration | Yes | No | No | No |
| Parameter objects | Yes | No | Yes | No |
| Automatic cleanup | Yes | No | Yes | Yes |
## Performance
Benchmarks comparing godi with [dig](https://github.com/uber-go/dig) (Uber's DI, powers Fx) and [do](https://github.com/samber/do) (samber's DI).
Run on Apple M2 Max. [Source code](benchmarks/comparison_test.go).
### Singleton Resolution
| Library | ns/op | B/op | allocs/op | vs godi |
| ------- | ----: | ---: | --------: | ------: |
| godi | 55 | 0 | 0 | 1x |
| do | 180 | 192 | 6 | 3.3x |
| dig | 640 | 736 | 20 | 12x |
godi uses a lock-free cache with **zero allocations**. Singletons are created at build time, so every resolution is a fast cache lookup.
### Concurrent Resolution
| Library | ns/op | B/op | allocs/op | vs godi |
| ------- | ----: | ---: | --------: | ------: |
| godi | 7 | 0 | 0 | 1x |
| do | 297 | 224 | 6 | 42x |
| dig | 366 | 736 | 20 | 52x |
Under high concurrency, godi is **40-50x faster** with zero contention.
### Transient Resolution
| Library | ns/op | B/op | allocs/op |
| ------- | ----: | ---: | --------: |
| godi | 176 | 40 | 2 |
| do | 188 | 208 | 7 |
New instance created on each call.
### Cold Start
| Library | ns/op | B/op | allocs/op | vs godi |
| ------- | -----: | -----: | --------: | ------: |
| godi | 17,500 | 21,064 | 155 | 1x |
| dig | 36,000 | 37,665 | 549 | 2.1x |
| do | 47,000 | 30,511 | 351 | 2.7x |
Full cycle: create container, register services, build, resolve. godi is **2x faster** than dig.
Run benchmarks yourself
```bash
cd benchmarks && go test -bench=. -benchmem
```
## Documentation
**[Full Documentation](https://godi.readthedocs.io)**
- [Getting Started](https://godi.readthedocs.io/en/latest/getting-started/) - 5-minute tutorial
- [Core Concepts](https://godi.readthedocs.io/en/latest/concepts/) - Lifetimes, scopes, modules
- [Features](https://godi.readthedocs.io/en/latest/features/) - Keyed services, groups, parameter objects
- [Integrations](https://godi.readthedocs.io/en/latest/integrations/) - Gin, Chi, Echo, Fiber, net/http
- [Guides](https://godi.readthedocs.io/en/latest/guides/) - Web apps, testing, error handling
- [API Reference](https://pkg.go.dev/github.com/junioryono/godi/v4)
## Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
## License
MIT License - see [LICENSE](LICENSE) for details.