Production Checklist
Run through this before pointing real traffic at a What app. Most items are a single line in what.toml; the framework's secure defaults do the rest.
Authentication & secrets
- Set a real
jwt_secret. Without one, tokens are verified against a random per-process key that changes on restart. Keep it out of source — use an environment variable.[auth] jwt_secret = "${JWT_SECRET}" - Never commit secrets. No
.env, no keys, no database files in git.
Sessions & CSRF
- Serve over HTTPS and keep secure cookies on. The
Secureflag is auto-disabled only in dev (localhost has no TLS); in production it should stay on.[session] secure = true - CSRF is automatic — tokens are injected into every form and validated on POST. Nothing to configure, but don't strip the hidden
_csrffield from custom forms.
Authorization
- Review your collection policies. Collections are owner-protected by default (create open, update/delete owner-only). Confirm each collection's
read/update/deleterules match your intent, and add tenantfilters for multi-org data. See Authorization. - Lock shared-write collections deliberately — if strangers should edit shared records, that must be an explicit
update = "all", not an accident.
Limit exposure
- Turn off the source viewer (it's off by default). Only enable
[server] source_viewer = trueif you intend the/w-source/*route to be public. - Run with
--production, which disables live reload, debug meta tags, and the source viewer in one flag.run-what dev --production --path . --port 8080 - Keep rate limits on for login, uploads, and actions (
[rate_limit]) to blunt abuse and brute-force.
Data & backups
- Back up your database. For SQLite, that's the
.dbfiles (app data and sessions) — snapshot them on a schedule. For D1/Supabase, use the provider's backup tooling. - Persist the data directory across deploys and container restarts — don't let it live in an ephemeral layer.
Build & deploy
- Choose the right target. A fully static site can ship via
run-what build; anything with sessions, forms, auth, or live data needs the dynamic server. See Build & Deploy. - Pick a CSS mode.
[server] css = "full"(default),"minimal", or"none"depending on how much of the framework stylesheet you ship. - Set a health check against a known route so your orchestrator can tell the app is up.
One-minute sanity pass: secret set • HTTPS + secure cookies • policies reviewed • source viewer off • rate limits on • database backed up. If all six are true, you're in good shape.