Database
Lifecycle and DI
Container registration graph and lifecycle semantics for database services
Preferred Pattern
Use constructor registration and type-based injection as the default style.
// Register constructors
forge.ProvideConstructor(c, func(db *Database, logger forge.Logger) *UserService {
return &UserService{db: db, logger: logger}
})
// Resolve by type (no string keys needed)
userService, err := forge.InjectType[*UserService](c)
eventBus, _ := vessel.InjectType[interfaces.EventBus](app.Container())Extension Registration Graph
database.Extension.Register(app) performs:
- configuration load and validation
- eager registration of
*DatabaseManager - registration of default
Databaseaccessor - registration of type-specific accessor for default DB type:
- SQL default ->
*bun.DB - Mongo default ->
*mongo.Client - Redis default ->
redis.UniversalClient
- SQL default ->
Key Service Identifiers
Constants in package:
database.ManagerKeydatabase.DatabaseKeydatabase.SQLKeydatabase.MongoKeydatabase.RedisKey
Primary resolution path in modern code should still be type-based helpers.
Runtime Lifecycle
DatabaseManager.Start(ctx):- marks manager started
- opens all registered databases (idempotent)
DatabaseManager.Stop(ctx):- marks manager stopped
- closes all databases
DatabaseManager.Health(ctx):- fails if any registered database is unhealthy
Extension-level lifecycle methods only mark extension started/stopped; manager owns connection lifecycle.
Recommended Access Patterns
By Type + Name (Best for multi-db)
manager, _ := database.GetManager(app.Container())
primary, _ := manager.SQL("primary")
analytics, _ := manager.Mongo("analytics")
cache, _ := manager.Redis("cache")Through Helpers
primary, _ := database.GetSQL(app.Container(), "primary")
cache, _ := database.GetRedis(app.Container(), "cache")App-Level Convenience
primary, _ := database.GetSQLFromApp(app, "primary")When Registering Your Own Services
Inject *database.DatabaseManager and resolve named DBs inside constructors. This keeps your service constructors explicit and avoids implicit assumptions about default DB type.
How is this guide?