App
Configuration And Secrets
Use environment variables and development secrets without coupling the app to a deployment platform.
Configure the listen address
GoLazy reads ADDR, then PORT, then defaults to 127.0.0.1:3000:
ADDR=127.0.0.1:4000 lazy
PORT=4000 ./sample-app
Use ADDR when you want to control the host and port together. Use PORT
when the deployment platform supplies only a port.
Set CONTROL_PLANE_ADDR when GoLazy should expose liveness and readiness probes
on a separate address, or when the environment should activate the default
control plane for ListenAndServe.
Read app-owned configuration
Use golazy.dev/lazyconfig when several environment variables belong together:
type AppConfig struct {
MailFrom string `var:"MAIL_FROM" require:"for sending mail"`
Port int `default:"3000"`
Listeners []Listener
}
type Listener struct {
Name string
Port int
}
config, err := lazyconfig.Getenv[AppConfig]()
if err != nil {
return err
}
For package-level config that should fail during startup when the environment is
invalid, use MustGetenv:
var Config = lazyconfig.MustGetenv[AppConfig]()
Field names map to uppercase snake-case environment variables, so Port reads
PORT and ListenAddr reads LISTEN_ADDR. Use var to name a variable
explicitly, default for fallback values, and required:"true" or
require:"for reason" for required values. If the config type implements
Validate() error, GoLazy calls it before returning.
Values are trimmed before parsing. Fields can be strings, numeric types, bools,
numeric or bool pointers, or []string. Unset pointer fields stay nil.
[]string values split on commas or whitespace. Bool fields treat yes,
true, and 1 as true; no, false, 0, and unknown values are false.
Bool matching is case-insensitive.
Slices use a singular field prefix. This fills two Listeners entries and
sorts them by number:
LISTENER_0_NAME=http
LISTENER_0_PORT=123
LISTENER_1_NAME=smtp
LISTENER_1_PORT=25
For a single item, omit the number:
LISTENER_NAME=http
LISTENER_PORT=123
The framework does not require a specific secret manager. Production deployments should provide real configuration values through the platform or secret store.
Environment variables
PRODUCTION ENVIRONMENT
ADDR: full listen address forlazyor the built app, such as0.0.0.0:8080.PORT: listen port used when the platform provides a port without a host. GoLazy readsADDRfirst, thenPORT, then defaults to127.0.0.1:3000.CONTROL_PLANE_ADDR: optional control-plane listen address. When it differs from the app address,ListenAndServestarts a second server for control endpoints. When it matches the app address, GoLazy mounts control endpoints into the app server.
Telemetry uses OpenTelemetry-compatible OTEL_* variables. See
Telemetry for activation rules and the complete
environment variable list.
DEVELOPMENT ONLY
SAMPLE_APP_ENV: ordinary checked-in development value frommise.toml.SAMPLE_APP_DEVELOPMENT_SECRET: secret-shaped checked-in example from.secrets/development.env.
Development-mode framework behavior comes from the lazydev build tag set by
lazy, not from sample-app environment flags.
Keep development examples local
The sample app includes development tooling and a hidden directory for local secret examples:
mise.toml
.secrets/development.env
Use mise.toml for ordinary local values and .secrets/development.env for
secret-shaped local examples. Do not depend on mise in production; the
production process should receive environment variables from its runtime
environment.
Pass configuration into services
Prefer explicit service constructors when configuration affects behavior:
type MailerConfig struct {
From string
}
func NewMailerFromEnv() (*Mailer, error) {
return NewMailer(MailerConfig{
From: os.Getenv("MAIL_FROM"),
})
}
Initialize the service once in Context, then expose it through typed context
helpers.