Deploy to Fly.io
Runs the Docker image close to your users, with a real disk if you need one.
A single Go binary you want in several regions without running servers. The best fit for Grit’s single-binary mode.
Teams that want a click-through dashboard for everything — Fly is CLI-first and expects you to read a TOML file.
Setup
- 1
Launch without deploying
Let Fly detect the Dockerfile and write a fly.toml, but stop before it ships anything — the defaults need two changes first.
fly launch --no-deploy - 2
Point the health check at the API
Fly checks `/` by default. Grit serves its health endpoint at `/api/health`, so without this the machine is marked unhealthy and cycled forever while the app is running perfectly.
[http_service]internal_port = 8080force_https = trueauto_stop_machines = "suspend"auto_start_machines = truemin_machines_running = 1[[http_service.checks]]interval = "15s"timeout = "3s"grace_period = "10s"method = "GET"path = "/api/health" - 3
Attach Postgres and Redis
Attaching sets DATABASE_URL for you. Redis comes from Upstash through Fly and gives you REDIS_URL.
fly postgres create --name my-app-dbfly postgres attach my-app-dbfly redis create - 4
Set the secrets
Secrets are encrypted and injected at runtime. Setting them triggers a redeploy, so do it before the first one.
fly secrets set \JWT_SECRET="$(openssl rand -base64 32)" \APP_ENV=production \CORS_ORIGINS="https://your-domain.com" - 5
Deploy, then migrate
Grit does not auto-migrate on boot in production — a process that rewrites the schema every time it restarts is a bad idea when the platform can restart it for its own reasons. Run migrations as an explicit step.
fly deployfly ssh console -C "/app/migrate"
What catches people out
Machines suspend on idle by default. The first request after a quiet period pays the wake-up cost — set `min_machines_running = 1` for anything user-facing.
A volume is attached to one machine in one region. Scale past one machine and each gets its own empty disk, so uploads must go to S3/R2 rather than local storage.
Fly Postgres is an unmanaged Postgres you own, not a managed service. Backups are your job — `fly postgres` will not do point-in-time recovery for you.
Platform dashboards and CLI flags change faster than these docs. For anything that looks different from what is written here, Fly.io's own documentation is the authority: fly.io/docs/
