Fly.io Deployment Cheat Sheet
flyctl commands, fly.toml configuration, and scaling patterns for deploying apps and machines to Fly.io regions.
Launch a New App
Bootstrap a fly.toml and provision an app from an existing project directory.
fly auth login# Detects your framework/Dockerfile and generates fly.tomlfly launch --name my-app --region iad --no-deploy# Deploy itfly deploy
fly.toml Essentials
Minimal config for an HTTP service with a health check.
app = "my-app"primary_region = "iad"[build] dockerfile = "Dockerfile"[http_service] internal_port = 8080 force_https = true auto_stop_machines = true auto_start_machines = true min_machines_running = 1[[http_service.checks]] interval = "15s" timeout = "2s" grace_period = "5s" method = "GET" path = "/health"
Scaling & Secrets
Adjust machine count/size and manage runtime secrets.
# Scale out to 3 machines and set VM sizefly scale count 3fly scale vm shared-cpu-2x --memory 512# Set a secret (triggers a redeploy with the new value)fly secrets set DATABASE_URL="postgres://user:pass@host/db"# Attach a managed Postgres clusterfly postgres create --name my-app-dbfly postgres attach my-app-db
Core Concepts
Terminology specific to Fly.io's Machines-based platform.
- Machine- a fast-booting Firecracker microVM running your container
- Region- deploy the same app across multiple regions for low latency
- fly.toml- per-app config: build, services, checks, mounts
- Volumes- persistent, region-pinned storage attached to a machine
- flyctl- the CLI for deploy, scale, logs, ssh, and secrets
Multi-Region Rollout & Regional Volumes
Spread machines across regions and pin persistent volumes to the region that serves them.
# Add backup regions so new machines can be scheduled therefly regions add lhr syd --group webfly regions list# Volumes are region-pinned - create one per region you write fromfly volumes create data --region lhr --size 10 --count 1fly volumes create data --region syd --size 10 --count 1# Confirm machine-to-region placement after scalingfly machine list --region lhr
Private Networking: 6PN & Flycast
Expose a service only on Fly's internal WireGuard mesh instead of the public internet.
# fly.toml - internal-only service, no public [[services.ports]] block[[services]] internal_port = 5432 protocol = "tcp" [[services.tcp_checks]] interval = "15s" timeout = "2s"# Other apps in the same org reach this app privately at:# my-app.internal (6PN - per-machine, DNS round-robin)# my-app.flycast (anycast, load-balanced virtual IP)
Deploy Strategy & Pre-Deploy Migrations
Run a release command before traffic shifts, and choose how machines are replaced.
[deploy] # Runs once, in a fresh machine, before the new version receives traffic release_command = "npm run migrate" # bluegreen: full new fleet is health-checked before old fleet is removed # canary: one machine takes traffic first, then the rest follow # immediate: replace machines in place (fastest, briefly less safe) strategy = "bluegreen"
Inspect & Roll Back Releases
List release history and redeploy a known-good image by digest.
# Every deploy is an immutable, addressable releasefly releases# Roll back by deploying the exact image from a prior releasefly deploy --image registry.fly.io/my-app:deployment-01HXYZ0000# Watch machine health during the switchfly status --watch
Advanced Platform Concepts
Terminology you'll hit once you move past a single-region toy deploy.
- 6PN- Fly's private IPv6 WireGuard network connecting all machines in an org
- Flycast- an anycast private IP that load-balances across an app's machines internally
- fly-replay- a response header that lets one region proxy a request to another region/app
- Machine states- created, starting, started, stopping, stopped, destroyed - each billable differently
- Anycast- your app's public IP is announced from every Fly edge simultaneously
- Process groups- named machine groups (e.g. `app`, `worker`) scaled and configured independently
Set `auto_stop_machines = true` with `min_machines_running = 0` for low-traffic services — Fly.io will suspend idle machines and resume them on the next request, cutting compute cost to near zero without changing your deploy config.