Reference

Configuration

Every environment variable of every kit config struct, grouped.

Kit packages never read env vars on their own: each package exports a Config struct, which you compose in your project's internal/platform/config/config.go and load with envconf.MustLoad[config.Config](). See the configuration concept. In development a .env file is read; real environment variables always win.

There is no GPSYSTEM_* namespace. Variable name prefixes are determined not by the kit but by the composing struct's envPrefix tag: the DB_, S3_, MAIL_ etc. prefixes are conventions of the generated project. The same struct mounts under a different prefix too, envconf.LoadPrefixed[dbx.Config]("ANALYTICS_DB_") maps the same struct onto a different variable set.

A generated project's config composes like this:

internal/platform/config/config.go
type Config struct {
    Server server.Config                 // no prefix: LISTEN_ADDR, ...
    DB     dbx.Config    `envPrefix:"DB_"`
    Worker worker.Config                 // WORKER_* + embedded REDIS_/SCHEDULER_
    Outbox outbox.Config `envPrefix:"OUTBOX_"`
    // added by hand when needed:
    Storage s3.Config     `envPrefix:"S3_"`
    Mail    smtp.Config   `envPrefix:"MAIL_"`
    JWT     auth.Config   `envPrefix:"JWT_"`
}

server.Config: no prefix

Lifecycle and limits of the HTTP server, regardless of engine. See Server.

VariableDefaultMeaning
LISTEN_ADDR:3000the address the engine (Fiber or chi) listens on
SHUTDOWN_TIMEOUT10sgraceful shutdown budget: after SIGINT/SIGTERM, in-flight requests get this long
READ_HEADER_TIMEOUT5slimit for receiving the request headers (separate only on the net/http-based chi; Fiber folds it into READ_TIMEOUT), the primary Slowloris defense
READ_TIMEOUT30slimit for reading the whole request (headers + body)
WRITE_TIMEOUT0slimit for writing the response; disabled by default because it would also cut off streaming/large downloads. Enable it when all your endpoints are short-lived
IDLE_TIMEOUT120show long an idle keep-alive connection stays open
CORS_ORIGINS*comma-separated allowed origins
BODY_LIMIT4194304max request body size in bytes (4 MiB); a value ≤ 0 also means the default, the cap can never be disabled by accident
HTTP_EXPOSE_INTERNAL_ERRORSfalse5xx responses include the underlying error message, stack, and wrap chain (development only); deliberately decoupled from OTEL_DEV_MODE

telemetry.Config: nested, no prefix

server.Config.Telemetry and worker.Config.Telemetry both carry the telemetry.Config{Otel, Log, Sentry} trio; telemetry.Setup composes the three subsystems in one call. See the observability overview. All variables are read under standard names at the top level, regardless of nesting depth.

otelx.Config: OTel bootstrap

See OpenTelemetry.

VariableDefaultMeaning
OTEL_SERVICE_NAMErequiredrequired unless dev mode: service.name on all telemetry
OTEL_SERVICE_VERSIONdevservice.version resource attribute
OTEL_DEV_MODEfalsetrue → no OTel exporters are created (unless Sentry tracing supplies one)
Exporter endpoints deliberately do not live in the kit's config: the standard OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_TRACES_EXPORTER etc. variables apply (via OTel's autoexport package); deployments configure the kit the same way as any other OTel-instrumented application.

logx.Config: the default slog logger

See Logging.

VariableDefaultMeaning
LOG_LEVELINFOminimum slog level (DEBUG/INFO/WARN/ERROR)
LOG_STDOUTfalsein prod mode, logs are also written to stdout (besides the OTLP bridge); leave it off when a collector scrapes container output too, or logs are ingested twice
LOG_FORMATemptyconsole format: empty/auto → text (dev) or JSON (prod); monolog → PHP/Monolog-style lines with full-path stack traces (logx/monolog); any other value fails at startup

sentryx.Config: the optional Sentry integration

See Sentry.

VariableDefaultMeaning
SENTRY_DSNemptyempty → the integration is fully disabled, every hook is a no-op
SENTRY_ENVIRONMENTdevelopment in dev mode, production otherwiseenvironment tag on Sentry events
SENTRY_TRACEStrueOTel spans are also shipped to Sentry (as an additional exporter); false when a collector forwards them, sampling is governed by OTEL_TRACES_SAMPLER, not a separate Sentry rate
SENTRY_DEBUGfalsethe Sentry SDK's own debug logging to stderr

dbx.Config: envPrefix:"DB_"

PostgreSQL connection, see the database overview.

VariableDefaultMeaning
DB_HOSTlocalhost
DB_PORT5432
DB_USERrequired
DB_PASSWORDrequired
DB_NAMErequireddatabase name
DB_SSLMODEdisable
DB_MAX_CONNS10maximum connections of the pgx pool
dbx.Config's package-level default is DB_HOST=localhost, but a generated project's .env.example ships DB_HOST=postgres: the app runs inside the compose dev stack, and postgres is the compose service's DNS name. Likewise queue.Config's REDIS_ADDR default is localhost:6379, while the generated .env.example ships redis:6379.

Named connections

Each named connection (add db <module> <name>) adds another dbx.Config under DB_<NAME>_*, the same variables and defaults as above, with the connection's (uppercased) name spliced into the prefix. add db news analytics adds:

VariableDefaultMeaning
DB_ANALYTICS_HOSTlocalhost
DB_ANALYTICS_PORT5432
DB_ANALYTICS_USERrequired
DB_ANALYTICS_PASSWORDrequired
DB_ANALYTICS_NAMErequireddatabase name
DB_ANALYTICS_SSLMODEdisable
DB_ANALYTICS_MAX_CONNS10maximum connections of this connection's own pgx pool

auth.Config: envPrefix:"JWT_"

JWT issuing and verification, see Authentication.

VariableDefaultMeaning
JWT_SECRETrequiredsigning key, distinct per service/environment
JWT_ACCESS_TOKEN_TTL15maccess token lifetime
JWT_REFRESH_TOKEN_TTL168hrefresh token lifetime
JWT_ISSUERemptyempty → the iss check is disabled; when set, Parse requires a matching iss
JWT_AUDIENCEemptyempty → the aud check is disabled; when set, Parse requires the token's aud claim to contain it
Set JWT_ISSUER and JWT_AUDIENCE (and use a distinct secret per service) so a token minted for another service or environment cannot be replayed.

s3.Config: envPrefix:"S3_"

S3-compatible object storage, see Storage.

VariableDefaultMeaning
S3_ENDPOINTemptyempty → AWS S3; for MinIO/RustFS the service address
S3_REGIONus-east-1
S3_BUCKETrequired
S3_ACCESS_KEY / S3_SECRET_KEYemptyboth empty → default AWS credential chain (IAM role etc.)
S3_USE_PATH_STYLEfalse/bucket/key addressing instead of virtual hosts, true for most self-hosted S3
S3_PUBLIC_BASE_URLemptybase for URL() (CDN or public bucket endpoint)

smtp.Config: envPrefix:"MAIL_"

SMTP sending and default sender, see Email.

VariableDefaultMeaning
MAIL_HOSTrequiredSMTP server address
MAIL_PORT587
MAIL_USERNAME / MAIL_PASSWORDemptyboth empty → no auth (Mailpit, internal relays)
MAIL_AUTHautoauth mechanism: auto (discover) | plain | login | cram-md5 | none
MAIL_TLSstarttlsstarttls (mandatory STARTTLS) | starttls-opportunistic (dev, TLS-less server) | tls (implicit TLS, port 465) | none
MAIL_FROM_ADDRESSrequireddefault sender address
MAIL_FROM_NAMEemptydefault sender display name
MAIL_TIMEOUT15sdial/send limit per send

queue.Config: envPrefix:"REDIS_"

The queue's (asynq's) Redis connection, see Queue.

VariableDefaultMeaning
REDIS_ADDRlocalhost:6379Redis host:port
REDIS_PASSWORDemptyempty → no auth
REDIS_DB0Redis logical database

outbox.Config: envPrefix:"OUTBOX_"

The relay's behavior, see Outbox.

VariableDefaultMeaning
OUTBOX_POLL_INTERVAL1ssleep between polls when a batch is not full
OUTBOX_BATCH_SIZE100rows claimed per poll (FOR UPDATE SKIP LOCKED)
OUTBOX_RETENTION168hhow long published rows are kept before cleanup
OUTBOX_CLEANUP_INTERVAL1hhow often published rows past retention are purged
OUTBOX_TASK_RETENTION24hasynq retention / TaskID dedup window on published tasks

scheduler.Config: envPrefix:"SCHEDULER_"

The scheduled-job runner, see Scheduler.

VariableDefaultMeaning
SCHEDULER_TIMEZONEUTCIANA timezone cron specs are evaluated in (e.g. Europe/Budapest)
SCHEDULER_LEASE_TTL15sleader lease TTL; the leader renews every TTL/3, the longest a lost leader can keep firing before another replica takes over
SCHEDULER_NAMESPACEgpsystemnamespace of the leader-election key in Redis, set it to a name unique to the app when multiple applications/environments share one Redis

worker.Config: the cmd/worker binary

Its own WORKER_-prefixed fields, plus embedded: queue.Config (REDIS_), scheduler.Config (SCHEDULER_) and telemetry.Config (standard OTEL_*/LOG_*/SENTRY_*, see above). See Worker.

VariableDefaultMeaning
WORKER_CONCURRENCY10tasks processed simultaneously
WORKER_QUEUESdefault:1queue→weight map, e.g. critical:6,default:3,low:1 (higher-weight queues are served more often)
WORKER_STRICT_PRIORITYfalseserve higher-weight queues to exhaustion before lower ones
WORKER_SHUTDOWN_TIMEOUT30sgraceful drain; unfinished tasks are requeued by asynq and redelivered (at-least-once)
WORKER_DEFAULT_MAX_RETRY25retry budget for listener/job tasks that don't set their own (queue.MaxRetry)

The compose dev stack's env variables (not a kit Config field)

These are generated into .env.example by new project; they don't belong to any kit package's Config struct, they drive compose.yml/Dockerfile substitution and Traefik routing.

VariableDefaultMeaning
USER_ID / GROUP_ID1000the dev containers run as this host UID/GID (id -u/id -g), so files written into the bind-mounted source stay yours, not root's
APP_HOST<project>.localhostthe module services' Traefik Host() rule
MAILPIT_HOSTmailpit.<project>.localhostthe mailpit UI's Traefik host
RUSTFS_S3_HOSTrustfs.<project>.localhostthe rustfs S3 API's Traefik host
RUSTFS_CONSOLE_HOSTrustfs-console.<project>.localhostthe rustfs web console's Traefik host

The shipped MAIL_*/S3_* lines (MAIL_HOST=mailpit, S3_ENDPOINT=http://rustfs:9000, ...) match the smtp.Config/s3.Config prefixes above: the mailpit/rustfs compose services boot with these, but wiring them (adding the fields to the project's config.go) stays opt-in.

Copyright © 2026