
The Machines resource API documents every endpoint. This guide covers the patterns you’ll actually need when building on it: cloning machines, keeping them in sync with
flyctl, configuring services, managing auto-stop/start behavior, and updating config.fly deploy. This guide is for when you need programmatic control, when you’re building a platform, managing machines from your own code, or doing things flyctl doesn’t support directly.
Before you begin
You need a Fly.io API token. Set it as an environment variable:https://api.machines.dev/v1. All requests need the Authorization header:
Create a Machine from an existing one
The most reliable way to create a Machine via the API is to start from an existing Machine’s configuration. This is especially useful if you need the new Machine to behave like one created byfly launch or fly deploy. Those commands set metadata, services, and other config that can be easy to miss if you build the JSON from scratch.
The workflow:
-
Get the source Machine’s config. Use the API or flyctl:
- Modify the JSON for your needs — change the region, adjust resources, update environment variables.
-
Create the new Machine by POSTing the modified config:
fly machine run with command-line flags, but if you’re starting from a full JSON config, the API is more straightforward.
Make API-created Machines visible to flyctl
Machines created directly through the API are “detached” by default if you build the config from scratch or strip the metadata. They exist and run, butfly deploy and fly scale won’t touch them since those commands only manage Machines that belong to a process group. Note that if you create a Machine by copying an existing flyctl-managed Machine’s config, the fly_platform_version and fly_process_group metadata carry over, so the new Machine is automatically part of the process group.
To bring a Machine under flyctl management, set two metadata keys:
fly_platform_version: must bev2fly_process_group: the name of an existing process group (e.g.,app,worker)
fly deploy will update it along with the rest of the group. Note that until the next deploy, the Machine won’t show a VERSION in fly status.
If you want Machines to stay independent of flyctl — for example, one-off workers or machines managed entirely by your own tooling, then leave the metadata off. Keep in mind that fly status will list them as detached.
Configure services via the API
Infly.toml, you define how traffic reaches your app using [http_service] or [[services]]. The API equivalent is the services property in the Machine config.
The services config controls how the Fly proxy routes connections to your Machine: ports, protocols, concurrency limits, and auto-stop/start behavior. Here’s a typical example:
Important: Within a process group, every Machine must have identical service configuration. The Fly proxy expects consistency: if Machine A accepts connections on port 8080 with a hard limit of 25, and Machine B has different settings, routing behavior becomes unpredictable.
Update a Machine’s configuration
The Machines API doesn’t supportPATCH — you can’t send just the fields you want to change. Instead, the update flow is:
-
GET the full Machine config:
-
Extract and modify the
configobject from the response — add a service, change an environment variable, adjust resources. -
Wrap and POST the modified config back. The GET response returns the config nested inside the Machine object, but the POST endpoint expects a
{"config": ...}wrapper at the top level:Whereupdated-config.jsonlooks like:
fly deploy) may have changed the Machine’s config in the meantime.
Note: Updating a Machine’s config triggers a stop/start cycle. It’s not a hot reload. Plan for brief downtime when updating running Machines.
Auto-stop, autostart, and suspend
The Fly proxy can automatically stop or suspend idle Machines and restart them when requests arrive. This is configured per-Machine in theservices property, the API equivalent of auto_stop_machines and auto_start_machines in fly.toml.
The relevant fields in each service entry:
How the proxy decides to stop a Machine
The proxy tracks active connections. When a Machine has zero connections and other Machines in the same process group can handle the load, the proxy considers it excess capacity and triggers an autostop. Theconcurrency.soft_limit is the threshold. Once total connections across the group drop low enough that a Machine is unnecessary, it gets stopped or suspended.
Even if a Machine is the only one in its region, it can still be stopped. If it has zero connections and autostop is enabled, the proxy will stop or suspend it. It will automatically start again on the next request if autostart is enabled.
Stop vs suspend: Stopped Machines boot from scratch on restart, so expect a cold start. Suspended Machines preserve memory state and resume faster, but not all workloads support suspend cleanly (Read more about common issues like clock skew after resume).
Keep autostart and autostop in sync
If you enableautostop but disable autostart, Machines will stop and never come back. Requests will return 503. If you enable autostart but disable autostop, Machines that get started will stay running indefinitely and never scale back down. In general, set both or neither.
Long-running background work
This is the most common gotcha. If your Machine receives an HTTP request, spawns a background task, and returns a response immediately, the proxy sees zero active connections and may autostop the Machine, killing the background work. For more information about background workers, check out this guide. Approaches that work:- Hold the connection open. Stream progress back to the client or use long-polling so the connection stays active while work runs. The proxy won’t stop a Machine with active connections.
- Disable autostop for workers. Set
autostopto"off"and have your application callprocess.exit()(or equivalent) when work is complete. You manage the lifecycle; the proxy stays out of it. - Use a separate process group. Run workers as a different process group with
autostop: "off"while your web-facing Machines use normal autostop. This way cost savings apply to the web tier without affecting background processing.
Machines without services
If a Machine has noservices config (no HTTP or TCP services), the Fly proxy doesn’t manage it at all. It won’t auto-stop or auto-start — it just runs until you stop it via the API, or it exits on its own. Its lifecycle is governed entirely by its restart policy.
This is the right setup for cron-style jobs, queue workers that poll for work, or anything that doesn’t accept inbound connections.
Setting a restart policy
Machines without services manage their own lifecycle through restart policies. Set the restart policy in the Machine config:"no"— don’t restart on exit"always"— always restart on exit"on-failure"— restart only on non-zero exit, up tomax_retries
Operations not supported by the Machines API
The Machines REST API covers Machine lifecycle and most app-level operations. A few peripheral operations still require the GraphQL API, such as those relating to organizations and provisioning custom networks. The GraphQL API is an internal interface used byflyctl with no stability guarantees, so it can change without notice.
When possible, shell out to flyctl itself rather than hitting the GraphQL API directly. The CLI flags are a more stable interface than the underlying API.
If you can’t use flyctl (for example, your system can’t execute shell commands during setup), you can reverse-engineer the GraphQL calls:
flyctl updates.
Related reading
- Machines API reference — full endpoint documentation
- Working with the Machines API — authentication, rate limits, and connection details
- Machine states and lifecycle — how Machines move between states
- fly.toml configuration reference — the flyctl-managed equivalent of API config