Dependency Injection
Nimbus ships with an IoC (Inversion of Control) container inspired by Laravel conventions. It lives in container.Container and is available as app.Container after nimbus.New().
Binding types
| Method | Behavior | Use case |
|---|---|---|
Bind(name, fn) | New instance every call | Request-scoped, unique IDs |
Singleton(name, fn) | Created once, cached | DB connections, SDK clients |
Instance(name, value) | Pre-built value, no constructor | Config objects, loggers |
Transient bindings
app.Container.Bind("requestID", func() string {
return uuid.New().String()
})
id1, _ := app.Container.Make("requestID")
id2, _ := app.Container.Make("requestID")
// id1 != id2 (new value each time)
Singleton bindings
app.Container.Singleton("db", func() (*nimbus.DB, error) {
return database.Connect("sqlite", "app.sqlite")
})
db1, _ := app.Container.Make("db")
db2, _ := app.Container.Make("db")
// db1 == db2 (same pointer)
Instance bindings
Register a pre-built value directly without a constructor:
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
app.Container.Instance("logger", logger)
// Resolve later:
l := app.Container.MustMake("logger").(*slog.Logger)
Checking existence
if app.Container.Has("stripe") {
client := app.Container.MustMake("stripe").(*stripe.Client)
// use client
}
Resolving bindings
// Safe — returns (value, error)
val, err := app.Container.Make("db")
// Panic on error — use when you're confident the binding exists
db := app.Container.MustMake("db").(*nimbus.DB)
Plugin bindings (HasBindings)
Plugins can declare container bindings via the HasBindings interface. These are registered automatically during the plugin Register phase:
func (p *StripePlugin) Bindings(c *container.Container) {
c.Singleton("stripe", func() (*stripe.Client, error) {
return stripe.New(os.Getenv("STRIPE_SECRET_KEY"))
})
}
// Now any handler can resolve it:
client := app.Container.MustMake("stripe").(*stripe.Client)
Type-safe resolution pattern
Since Make returns any, write thin helpers for type safety:
func ResolveDB(c *container.Container) *nimbus.DB {
return c.MustMake("db").(*nimbus.DB)
}
// In handler:
db := ResolveDB(app.Container)