App

Configuration And Secrets

Use environment variables and development secrets without coupling the app to a deployment platform.

By Guillermo Alvarez - Published Updated

Configure the listen address

GoLazy reads ADDR, then PORT, then defaults to :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 secrets

Application code reads ordinary environment variables:

Sessions: lazysession.Config{
    Key: os.Getenv("SECURE_COOKIE_KEY"),
}

The framework does not require a specific secret manager. Production deployments should provide real values through the platform or secret store.

Environment variables

SECURITY

  • SECURE_COOKIE_KEY: signs session cookies. The sample app reads it from the process environment. Development commands receive the checked-in example value through mise; production deployments must provide their own value through the hosting platform or secret store.

PRODUCTION ENVIRONMENT

  • ADDR: full listen address for lazy or the built app, such as 0.0.0.0:8080.
  • PORT: listen port used when the platform provides a port without a host. GoLazy reads ADDR first, then PORT, then defaults to :3000.
  • CONTROL_PLANE_ADDR: optional control-plane listen address. When it differs from the app address, ListenAndServe starts a second server for control endpoints. When it matches the app address, GoLazy mounts control endpoints into the app server.

DEVELOPMENT ONLY

  • EXAMPLE_API_TOKEN: placeholder development token in secrets/development.env. It demonstrates local env loading and should not be used as production configuration.

Keep development examples local

The sample app includes development tooling and example secrets:

mise.toml
.secrets/development.env

Those files are for local commands. 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.