Configuration
All configuration is loaded by config.Load() in internal/config/config.go. Every value comes from an environment variable. There are no config files.
Warning
Variables marked Required in Prod have no default or have a default that will cause silent misbehaviour (wrong auth, no email, etc.) if left unset in production.
Database
| Variable |
Required in Prod |
Default |
Purpose |
DATABASE_URL |
Yes |
postgres://ftl_admin:localdev@localhost:5432/ftl2026?sslmode=disable |
PostgreSQL connection string (pgx DSN). api-server and flusher only; ws-server does not use Postgres. |
Redis
| Variable |
Required in Prod |
Default |
Purpose |
REDIS_URL |
Yes |
redis://localhost:6379 |
Redis connection string. Required by all three binaries. Startup fails if empty. |
Server
| Variable |
Required in Prod |
Default |
Purpose |
API_PORT |
No |
8080 |
Fiber listen port for api-server. |
WS_PORT |
No |
8081 |
Fiber listen port for ws-server. |
ENV |
Yes |
development |
Set to production to enable: Secure cookies, Google + Sportmonks key enforcement, disable dev auth endpoints. |
CORS_ORIGINS |
Yes |
http://localhost:5173,http://localhost:8080 |
Comma-separated allowed origins for CORS and WebSocket upgrade Origin check. |
DISABLE_RATE_LIMIT |
— |
unset |
Set to 1 only for load testing. See warning below. |
FLUSH_INTERVAL |
No |
100ms |
Flusher drain interval. Go duration string. |
Warning
DISABLE_RATE_LIMIT=1 in production removes all protection against credential stuffing, referral-code scraping, and API abuse. The ftl.sh local dev script sets this by default. Verify it is unset in every production deployment manifest before launch.
Auth — Google OAuth
| Variable |
Required in Prod |
Default |
Purpose |
GOOGLE_CLIENT_ID |
Yes |
"" |
Google OAuth client ID. Required in production (startup fails if ENV=production and this is empty). |
Auth — JWT
| Variable |
Required in Prod |
Default |
Purpose |
JWT_PRIVATE_KEY_B64 |
Yes |
none |
Base64-encoded RSA private key (PEM). Used by api-server to sign tokens. Generate with ftl-backend/scripts/gen-dev-keys.sh. Startup fails if missing (api-server calls RequireSigningKeys()). |
JWT_PUBLIC_KEY_B64 |
Yes |
none |
Base64-encoded RSA public key (PEM). Used by both api-server and ws-server to validate tokens. Startup fails if missing (enforced in config.validate()). |
JWT_ACCESS_EXPIRY |
No |
15m |
Access token lifetime. Go duration string. |
JWT_REFRESH_EXPIRY |
No |
168h |
Refresh token lifetime (7 days). |
JWT_WS_EXPIRY |
No |
60s |
WebSocket token lifetime. |
ADMIN_EMAILS |
No |
"" |
Comma-separated email addresses promoted to role=admin at startup and on login. |
Auth — Registration ticket
| Variable |
Required in Prod |
Default |
Purpose |
REG_TICKET_SECRET |
Yes |
"" |
HMAC secret for registration tickets. Minimum 32 characters. Startup fails if missing or too short (api-server calls RequireSigningKeys()). |
REG_TICKET_TTL |
No |
5m |
Registration ticket lifetime. Go duration string. |
Cookies
| Variable |
Required in Prod |
Default |
Purpose |
COOKIE_DOMAIN |
Yes |
"" |
Cookie Domain attribute. Set to apex domain in production (e.g. jetafutures.com) so cookies work across subdomains. |
Email (Azure Communication Services)
| Variable |
Required in Prod |
Default |
Purpose |
COMMUNICATION_SERVICE_CONNECTION_STRING |
Yes |
"" |
ACS connection string. If empty or malformed, api-server boots with NoopSender (no emails sent, logged at WARN). |
EMAIL_FROM |
Yes |
"" |
Sender address for transactional emails. |
EMAIL_LOGO_URL |
No |
https://ftl-logo.jetafifa2026.workers.dev/ |
Public URL of FTL logo PNG for email header. Must be reachable from email clients (use CDN). |
EMAIL_BACKGROUND_IMAGE |
No |
"" |
Optional background image URL for email card. Empty → brand-navy fallback. |
PROD_FRONTEND_URL |
No |
https://ftl.jetafutures.com/ |
Base URL for email CTAs ("Open FTL" button). |
Sportmonks
| Variable |
Required in Prod |
Default |
Purpose |
SPORTMONKS_API_KEY |
Yes |
"" |
Sportmonks API key. Required in production (startup fails). Without it, the scheduler is disabled and no live prices fire during matches. |
SPORTMONKS_BASE_URL |
No |
https://api.sportmonks.com |
Sportmonks API base URL. |
SPORTMONKS_SEASON_ID |
No |
26618 |
Season ID used for fixture queries. |
SPORTMONKS_LEAGUE_IDS |
No |
1122,648,1116,1082 |
Comma-separated league IDs to poll. At least one required. |
Trade settings
| Variable |
Required in Prod |
Default |
Purpose |
TRADE_SLIPPAGE_TOLERANCE_PCT |
No |
0.005 |
Slippage tolerance for CFD positions (0.5%). Passed to position_open.lua and position_close.lua. |
Noise (synthetic price jitter)
Noise adds small random price movements between real trades so the chart is not flat during quiet periods.
| Variable |
Required in Prod |
Default |
Purpose |
NOISE_ENABLED |
No |
true |
Enable server-side noise ticks. |
NOISE_INTERVAL_MS |
No |
2000 |
Milliseconds between noise ticks per instrument. |
NOISE_AMPLITUDE |
No |
0.002 |
Fractional price amplitude per tick (0.2%). |
NOISE_DELTA_SKIP_PCT |
No |
0.01 |
Suppress noise ticks whose delta is smaller than this fraction of current price. |
NOISE_SAMPLE_EVERY_N |
No |
100 |
Flusher only writes a noise tick to price_ticks every N noise events (avoids table bloat). |
Bot & synthetic trading
Warning
BOT_ENABLED=1 in production with a real BOT_WALLET means synthetic accounts trade real wallet points against your users. Bots are useful for liquidity testing but should be explicitly disabled or isolated in production unless you intend them to participate.
| Variable |
Required in Prod |
Default |
Purpose |
BOT_ENABLED |
No |
1 (enabled) |
Enable bot engine. Set to 0 in production unless bots are intentional. |
BOT_WALLET |
No |
500 |
Starting wallet balance for each bot persona. |
Feature toggles
| Variable |
Required in Prod |
Default |
Purpose |
FLUSHER_EMBEDDED |
No |
unset |
Set to 1 to run the flusher inside the api-server process (single-binary dev mode). In production, deploy the standalone cmd/flusher binary. |