A Fly Machine is a hardware-virtualized container — not just a Docker container, but a full KVM virtual machine running your OCI image. This provides:
- True hardware isolation (each Machine gets its own kernel)
- ~300ms cold start (fast enough to boot per HTTP request)
- Ephemeral or persistent (with Volumes for state)
- Per-second billing (pay only when running)
┌─────────────────────────────────┐
│ Machine States │
│ │
fly machine ────► created ──► starting ──► started │
create │ │ │ │
│ (health check) │ │
│ ▼ ▼ │
│ stopping ◄── stopped │
│ │ │
│ ▼ │
│ destroyed │
└─────────────────────────────────┘
- created — Machine is defined but not yet started
- starting — Machine VM is booting
- started — Machine is running and healthy
- stopping — Machine is shutting down
- stopped — Machine is idle (not billed for CPU)
- destroyed — Machine is deleted permanently
Fly exposes a REST API for direct Machine management, useful for programmatic scaling.
curl -X POST \
"https://api.machines.dev/v1/apps/my-app/machines" \
-H "Authorization: Bearer $(fly auth token)" \
-H "Content-Type: application/json" \
-d '{
"config": {
"image": "registry.fly.io/my-app:latest",
"guest": {
"cpu_kind": "shared",
"cpus": 1,
"memory_mb": 256
},
"services": [{
"ports": [{"port": 443, "handlers": ["tls", "http"]}],
"protocol": "tcp",
"internal_port": 8080
}]
},
"region": "ams"
}'fly machine start <machine-id>
fly machine stop <machine-id>
fly machine restart <machine-id>fly platform vm-sizesCommon sizes:
| Name | CPU | Memory | Notes |
|---|---|---|---|
shared-cpu-1x |
1 shared | 256 MB | Free tier eligible |
shared-cpu-2x |
2 shared | 512 MB | |
performance-1x |
1 dedicated | 2 GB | |
performance-2x |
2 dedicated | 4 GB | |
performance-4x |
4 dedicated | 8 GB |
Change size:
fly scale vm performance-1x
fly scale memory 1024 # set to 1GBA single Fly App can run multiple process groups — different Machine configurations for different roles.
Example fly.toml:
[processes]
app = "node server.js"
worker = "node worker.js"
[[services]]
processes = ["app"]
internal_port = 8080Scale independently:
fly scale count app=2 worker=1You can override the Docker CMD/entrypoint per-Machine:
fly machine run registry.fly.io/my-app:latest \
--entrypoint "/bin/sh" \
-e MY_VAR=helloFly can automatically:
- Stop machines when no traffic for N seconds (saves cost)
- Start machines when a new request arrives (~300ms cold start)
Configure in fly.toml:
[http_service]
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0 # allow 0 running when idleSet min_machines_running = 1 if you need guaranteed low latency (always-on).
fly ssh console # Connect to any running machine
fly ssh console -s # Select a specific machine interactively
fly ssh console --pty -C "env" # Run a command and returnInside any Machine, you can access identity via environment variables:
echo $FLY_APP_NAME # my-app
echo $FLY_MACHINE_ID # abc123
echo $FLY_REGION # ams
echo $FLY_IMAGE_REF # registry.fly.io/my-app:deployment-xyzOr via the Fly metadata API (available inside Machines only):
curl http://[fdaa::3]:8080/v1/metadata- Deploy any app.
- Run
fly machine listand note the Machine ID. - Run
fly machine status <id>for full details.
- Run
fly machine stop <id>. - Confirm
fly statusshows it as stopped. - Run
fly machine start <id>and confirm it recovers.
- Run
fly ssh console. - Execute
env | grep FLYto see all Fly-injected variables. - Run
ps auxto inspect running processes.
→ Continue to 500 — Configuration (fly.toml)