dix is a lightweight yet powerful dependency injection framework for Go.
Inspired by uber-go/dig, with support for advanced dependency management and namespace isolation.
| Feature | Description |
|---|---|
| π Cycle Detection | Auto-detect dependency cycles |
| π¦ Multiple Injection | Support func, struct, map, list |
| π·οΈ Namespace | Dependency isolation via map key |
| π― Multi-Output | Struct can provide multiple dependencies |
| πͺ Nested Support | Support nested struct injection |
| π§ Non-Invasive | Zero intrusion to original objects |
| π‘οΈ Safe API | TryProvide/TryInject won't panic |
| π Visualization | HTTP module for dependency graph |
go get github.com/pubgo/dix/v2package main
import (
"fmt"
"github.com/pubgo/dix/v2"
)
type Config struct {
DSN string
}
type Database struct {
Config *Config
}
type UserService struct {
DB *Database
}
func main() {
// Create container
di := dix.New()
// Register Providers
dix.Provide(di, func() *Config {
return &Config{DSN: "postgres://localhost/mydb"}
})
dix.Provide(di, func(c *Config) *Database {
return &Database{Config: c}
})
dix.Provide(di, func(db *Database) *UserService {
return &UserService{DB: db}
})
// Inject and use
dix.Inject(di, func(svc *UserService) {
fmt.Println("DSN:", svc.DB.Config.DSN)
})
}Register constructor (Provider) to container:
// Standard version - panics on error
dix.Provide(di, func() *Service { return &Service{} })
// Safe version - returns error
err := dix.TryProvide(di, func() *Service { return &Service{} })
if err != nil {
log.Printf("Registration failed: %v", err)
}Inject dependencies from container:
// Function injection
dix.Inject(di, func(svc *Service) {
svc.DoSomething()
})
// Struct injection
type App struct {
Service *Service
Config *Config
}
app := &App{}
dix.Inject(di, app)
// Safe version
err := dix.TryInject(di, func(svc *Service) {
// ...
})Control long-running providers during startup:
- Default provider timeout:
15s - Disable provider timeout explicitly:
dix.WithProviderTimeout(0) - Default slow provider warning threshold:
2s - Disable slow provider warning:
dix.WithSlowProviderThreshold(0)
di := dix.New(
// Default `ProviderTimeout` is `15s`
// Use `dix.WithProviderTimeout(0)` to disable provider timeout
// Default `SlowProviderThreshold` is `2s`
// Use `dix.WithSlowProviderThreshold(0)` to disable slow-provider warnings
dix.WithProviderTimeout(2*time.Second), // override default (default: 15s, 0 = disabled)
dix.WithSlowProviderThreshold(300*time.Millisecond), // override default (default: 2s, 0 = disabled)
)Enable step-by-step dependency resolution/injection/provider execution logs:
- Env var:
DIX_TRACE_DI - Default: disabled
- Enable values:
1,true,on,yes,enable,trace,debug
export DIX_TRACE_DI=trueWhen enabled, dix prints di_trace ... events with structured key-values (provider, input/output types, query kind, parent chain, timeout, etc.).
Note: if
DIX_LLM_DIAG_MODE=machine, human-readable text logs are suppressed by design, includingdi_tracelines.
You can collect detailed diagnostics into a searchable JSONL file:
- Env var:
DIX_DIAG_FILE - Example:
export DIX_DIAG_FILE=.local/dix-diag.jsonl
Behavior rules:
- If
DIX_DIAG_FILEis not configured, dix keeps the original behavior (no diagnostic file output). - If
DIX_DIAG_FILEis configured, dix appends diagnostic records to file (trace/error/llm). - Console verbosity still follows existing controls (
DIX_TRACE_DI,DIX_LLM_DIAG_MODE).
Tip:
- Keep console output concise for users.
- Keep detailed records in file for search/LLM/offline troubleshooting.
Starting from this version, dix also emits unified trace events into an in-memory trace store (dixtrace), which can be queried via HTTP API (/api/trace).
- Default: enabled (in-memory ring buffer)
- Optional file sink env var:
DIX_TRACE_FILE - Example:
export DIX_TRACE_FILE=.local/dix-trace.jsonl - Compatibility fallback: when
DIX_TRACE_FILEis not set andDIX_DIAG_FILEis set, trace file sink will reuseDIX_DIAG_FILEin append mode.
/api/trace is optimized for online troubleshooting (filter by operation/status/event/component/provider/output_type).
If you need separate trace-only file persistence, set DIX_TRACE_FILE explicitly.
Quick event dictionary:
| Event | Meaning |
|---|---|
di_trace inject.start |
Begin an injection request (component, param_type) |
di_trace inject.route |
Injection route selected (function or struct) |
di_trace provide.start |
Begin a provider registration request (component) |
di_trace provide.signature |
Provider function signature analyzed (input_count, output_count) |
di_trace provide.register.output.done |
Provider output type registered successfully |
di_trace provide.register.failed |
Provider registration failed (reason or error) |
di_trace resolve.value.search_provider.start |
Start searching providers for a dependency type |
di_trace resolve.value.found |
Dependency value resolved successfully |
di_trace resolve.value.not_found |
Dependency resolution failed (reason included) |
di_trace provider.execute.dispatch |
Provider selected for execution (provider, output_type, input_types) |
di_trace provider.input.resolve.start |
Resolve one provider input type |
di_trace provider.input.resolve.found |
Provider input resolved |
di_trace provider.input.resolve.failed |
Provider input resolution failed |
di_trace provider.call.start |
Start executing provider (timeout) |
di_trace provider.call.done |
Provider execution completed |
di_trace provider.call.failed |
Provider execution failed (timed_out, error) |
di_trace provider.call.return_error |
Provider returned non-nil error |
di_trace inject.func.resolve_input.start |
Resolve function injection argument |
di_trace inject.func.resolve_input.failed |
Function argument resolution failed |
di_trace inject.struct.field.resolve.start |
Resolve one struct field injection |
di_trace inject.struct.field.resolve.done |
Struct field injected successfully |
di_trace inject.struct.field.resolve.failed |
Struct field injection failed |
type In struct {
Config *Config
Database *Database
}
type Out struct {
UserSvc *UserService
OrderSvc *OrderService
}
// Multiple inputs and outputs
dix.Provide(di, func(in In) Out {
return Out{
UserSvc: &UserService{DB: in.Database},
OrderSvc: &OrderService{DB: in.Database},
}
})// Provide with namespace
dix.Provide(di, func() map[string]*Database {
return map[string]*Database{
"master": &Database{DSN: "master-dsn"},
"slave": &Database{DSN: "slave-dsn"},
}
})
// Inject specific namespace
dix.Inject(di, func(dbs map[string]*Database) {
master := dbs["master"]
slave := dbs["slave"]
})// Provide same type multiple times
dix.Provide(di, func() []Handler {
return []Handler{&AuthHandler{}}
})
dix.Provide(di, func() []Handler {
return []Handler{&LogHandler{}}
})
// Inject all
dix.Inject(di, func(handlers []Handler) {
// handlers contains AuthHandler and LogHandler
})Provides global singleton container for simple applications:
import "github.com/pubgo/dix/v2/dixglobal"
// Use directly without creating container
dixglobal.Provide(func() *Config { return &Config{} })
dixglobal.Inject(func(c *Config) { /* ... */ })Bind container to context.Context:
import "github.com/pubgo/dix/v2/dixcontext"
// Store in context
ctx := dixcontext.Create(context.Background(), di)
// Retrieve and use
container := dixcontext.Get(ctx)Web interface for visualizing dependency graph, designed for large projects:
import (
"github.com/pubgo/dix/v2/dixhttp"
"github.com/pubgo/dix/v2/dixinternal"
)
server := dixhttp.NewServer((*dixinternal.Dix)(di))
server.ListenAndServe(":8080")Visit http://localhost:8080 to view dependency graph.
Highlights:
- π Fuzzy Search - Quickly locate types or functions
- π¦ Package Grouping - Collapsible sidebar browsing
- π Bidirectional Tracking - Show both dependencies and dependents
- π Depth Control - Limit display levels (1-5 or all)
- π¨ Modern UI - Tailwind CSS + Alpine.js
See dixhttp/README.md for details.
# Run tests
task test
# Lint
task lint
# Build
task build| Example | Description |
|---|---|
| struct-in | Struct input injection |
| struct-out | Struct multi-output |
| func | Function injection |
| map | Map/namespace injection |
| map-nil | Map with nil handling |
| list | List injection |
| list-nil | List with nil handling |
| lazy | Lazy injection |
| cycle | Cycle detection example |
| handler | Handler pattern |
| inject_method | Method injection |
| test-return-error | Error handling |
| http | HTTP visualization |
| Document | Description |
|---|---|
| Design Document | Architecture and detailed design |
| Audit Report | Project audit, evaluation and comparison |
| dixhttp README | HTTP visualization module documentation |
MIT