Production Checklist
Production-readiness concerns are spread across many pages. This page collects them into one ordered checklist: each item states what to set, why, and the config key or API, then links to the page that documents it in depth.
Security
- Set
vef.security.secret. When unset, the framework generates an ephemeral per-process JWT signing key and logs a warning: tokens do not survive a restart and do not work across nodes. Generate a stable value withsecurity.GenerateSecret()and provision it per deployment; startup also warns when the value is the publicsecurity.DefaultJWTSecret. See Authentication Reference. - Set
vef.app.trusted_proxiesbehind a reverse proxy. With the list empty,X-Forwarded-Foris ignored and the client IP is the direct connection peer — behind a load balancer every request then shares the proxy's IP for rate-limit keys and IP whitelists. List only proxy IPs or CIDR ranges you control. See Configuration Reference. - Enable CORS deliberately. The CORS middleware is registered but inert
until
vef.cors.enabled = true; browser clients then need an explicitallow_originslist. See Configuration Reference. - Review the auth endpoint rate limits.
vef.security.login_rate_limitdefaults to6andrefresh_rate_limitto1(per key, 5-minute sliding window). Limiter state is in-memory per instance, so a multi-node deployment multiplies the effective limit by the node count. See Built-in Resources. - Keep
vef.mcp.require_authon. The MCP endpoint requires Bearer auth when the key is unset ortrue; only an explicitfalseallows anonymous access. See MCP. - Use a Redis nonce store for signature auth on multiple nodes. Signature
authentication defaults to an in-memory nonce store, so replay protection
is per process; supply
security.NewRedisNonceStorefor distributed deployments. See Authentication. - Size
vef.app.body_limit. The request body limit defaults to32mib; lower it when you do not accept large payloads, raise it deliberately when you do. See Configuration Reference.
Data
- Turn on database TLS.
ssl_modedefaults todisable; setrequire,verify-ca, orverify-full(plusssl_root_certfor a private CA) on every network data source. See Data Sources. - Consider
enable_sql_guard = true. Off by default. When enabled, dangerous raw-SQL statements (DROP,TRUNCATE,DELETE/UPDATEwithoutWHERE) are blocked unless the query context is whitelisted. See Data Sources. - Decide on Redis.
vef.redis.enableddefaults tofalse, which injects a nil client. What depends on Redis: theredis_streamevent transport (its constructor returns nil when the client is nil, so enabling the transport without enabling Redis silently leaves its routes unserved),cache.NewRediscaches (panic on a nil client), and the Redis nonce store from item 6. Challenge tokens are JWT-based and per-operation rate limits are in-memory, so neither needs Redis. See Configuration Reference.
Storage
- Set a real storage provider. With
vef.storage.providerunset, the framework falls back to in-memory storage and logs a warning — objects are lost on restart. Usefilesystemorminiofor any non-test deployment. See Storage. - Register a
FileACLbefore storing private files. The default ACL grants reads only underpub/and denies every other key regardless of who asks; override it viavef.SupplyFileACL(...)once you servepriv/*files. See Storage. - Route storage events through the outbox. The storage module fails fast
at startup unless
vef.storage.*events resolve to a transactional transport: enablevef.event.transports.outboxand add a routing rule, or makeoutboxthe default transport. See Storage.
Events
- Pick a production transport. The default
memorytransport is neither durable nor transactional: events are lost on crash or restart, and the default queue-full policy fails the publish withevent.ErrQueueFull. For anything that must survive the process, useoutbox(transactional, durable, at-least-once, publish-only, relays into a sink) and/orredis_stream(durable, at-least-once, cross-process). See Event Bus. - Plan for at-least-once semantics. Durable transports may deliver
duplicates: subscribe with
event.WithGroup(...)(required on at-least-once routes) and keep the Inbox middleware enabled for dedupe. See Event Bus.
Operations
- Verify shutdown grace periods.
vef.Runstops through the FX lifecycle on SIGINT/SIGTERM: the HTTP server gets a 30-second grace period for in-flight requests and the overall stop timeout is 60 seconds. Give your orchestrator at least that much termination grace. See Lifecycle. - Decide who may call
sys/monitor. Monitoring endpoints require Bearer auth by default (any authenticated principal, per-action rate-limit max60); add permission checks or network controls if host metrics are sensitive in your environment. See Monitor and Built-in Resources. - Set the log level.
VEF_LOG_LEVELacceptsdebug|info|warn|error(pluspanic); unrecognized values fall back toinfo, the default. See logx. - Inject build info. Generate build metadata with
vef-cli generate-build-infoand supply it viavef.Supply(BuildInfo); without it,sys/monitorreportsunknownfor app version, build time, and git commit. See CLI Tools and Monitor.
Optional modules
Skip the items for modules you do not enable.
- Set
vef.integration.secret_keybefore enablingvef.IntegrationModule. Without it, integration auth parameters and data-source passwords are stored in plaintext with only a startup warning. Picksecret_algorithm(aesdefault,sm4) deliberately — values sealed under one algorithm are unreadable under the other. Treatvef.security.api_keys/basic_accounts(the static credential maps behind theapi_key/http_basicstrategies) with the same secrecy. See Integration Engine. - Whitelist
vef.push.allowed_origins. The push endpoint allows every browser origin when the list is empty (the handshake is still token-authenticated; the whitelist is defense in depth). Multi-node deployments need Redis for the cross-node relay, and the relay refuses to start without a non-emptyvef.app.name. See Server Push. - Review cron store limits when enabling
vef.cron.store.run_timeoutdefaults to0(runs are unbounded) andrun_retentiondefaults to0(the journal is never pruned) — opt into both deliberately; startup validatesabandoned_after ≥ 2 × heartbeat_interval. See Durable Schedules. - Recount your Redis dependents. Beyond item 10, opaque-token
sessions (
security.NewRedisSessionStore) and the push relay also need Redis in multi-node deployments.
Next step
Read the Configuration Reference for
every key mentioned here, or Lifecycle for what
actually happens between vef.Run(...) and the first request.