go get github.com/hopeio/initialize@latestinitialize boots your process from configuration: it loads settings, builds clients (databases, caches, brokers, …), and exposes them on a typed global handle. You describe what you need as struct fields; the library wires how they are created.
main often becomes a script of viper.ReadInConfig, gorm.Open, redis.NewClient, retry loops, and cleanup. Environments differ, secrets move to a config center, and hot reload is bolted on later.
With initialize you:
- Define root settings (app name, env, local files, remote center).
- Declare a
Configstruct and aDaostruct. - Call
NewGlobal[Config, Dao](...). - Use
Global.Conf()/Global.Daoanddefer Global.Cleanup().
- Root vs business config — root chooses environment and sources; business fields come from local files and/or a center
- Environments —
dev/test/prodor any name you define - Local files — multiple paths, optional reload interval / file watch
- Remote centers — Nacos, Apollo, etcd, HTTP; register custom implementations
- Formats — Viper codecs (TOML, YAML, JSON, INI, dotenv, …)
- Overrides — struct tags for flags and environment variables
- DAO plugins — drop fields typed as contrib clients; they
Initfrom nested config - Lifecycle hooks —
BeforeInject,AfterInjectConfig,AfterInject(optional*WithRoot) - Template generation — emit a config skeleton from your structs
- Shutdown —
Cleanupcloses resources;Deferregisters extra teardown
go run ./_example -c _example/config/config.tomlpackage global
import (
"time""github.com/hopeio/initialize""github.com/hopeio/initialize/contrib/gormdb/postgres"
initredis "github.com/hopeio/initialize/contrib/redis"
)
typeConfigstruct {
initialize.EmbeddedPresetsHTTPstruct {
ReadTimeout time.Duration
}
}
func (c*Config) BeforeInject() {
ifc.HTTP.ReadTimeout==0 {
c.HTTP.ReadTimeout=5*time.Second
}
}
typeDaostruct {
initialize.EmbeddedPresetsDB*postgres.DBCache*initredis.Client
}
func (d*Dao) AfterInject() {
// register GORM callbacks, tune pools, …
}
varGlobal=initialize.NewGlobal[Config, Dao]()funcmain() {
deferglobal.Global.Cleanup()
db:=global.Global.Dao.DB_=db
}Name = "orders"Env = "dev"
[dev]
debug = true
[dev.localConfig]
Paths = ["local.toml"]
ReloadInterval = "2s"
[dev.ConfigCenter]
Format = "toml"Type = "nacos"Business keys ([HTTP], [DB], [Cache], …) live in local.toml or the remote document. Use SkipInjectDaos when a field should be skipped in a given environment.
Single-env apps can omit Env and pass -c path/to/config.toml.
With Watch = true (local files) or a config center attached, every change builds a brand-new Config snapshot, runs the full injection lifecycle on it, and publishes it atomically — the old object is never mutated in place:
Global.Conf()— returns the latest snapshot lock-free; the default accessor, call it on each use to observe reloads.- Need boot-time values (e.g. the listen address)? Read
Conf()once during startup and keep it yourself; the library does not retain a first-generation reference.
Published snapshots are immutable: never write to their fields. DAOs (connection-like resources) do not participate in hot reload.
| Method | Moment |
|---|---|
BeforeInject / BeforeInjectWithRoot | Defaults before decode |
AfterInjectConfig / AfterInjectConfigWithRoot | Config filled; DAO init pending |
AfterInject / AfterInjectWithRoot | All DAO fields ready |
Ship-ready field types under contrib/:
gormdb (mysql / postgres / sqlite) · redis · sarama · confluent · nats · nsq · etcd · elasticsearch · minio · mqtt · badger · pebble · bbolt · ristretto · influxdb · duckdb · flightsql · mail · apollo · nacos · viper
Custom type: implement DaoField (Config / Init / Closer) or use DaoG / DaoConfig.
Built-in: local multi-file, Nacos, Apollo, etcd, HTTP.
Extend with RegisterConfigCenter.