
Overview
We donāt have a Terraform provider anymore, and thatās intentional. Itās not a great fit for how our platform works. This guide is about how to get a Terraform-like experience using the tools that do fit. If youāre used to defining infrastructure declaratively, using templated variables, repeatable workflows, a single source of truth, you can absolutely have that on Fly.io. But youāll get there by thinking a little differently: using tools built around our actual primitives instead of trying to bend them to fit a plan/apply model. If youāre looking for a good path forward, youāve got options. This guide walks through two options for automating Fly.io deployments without Terraform. The first usesflyctl and GitHub Actions. Itās what we recommend for most users: push to main, your app gets deployed. No infra state to manage, no VMs to track. Just code and Git.
The second uses the Machines API directly. Itās more work, but gives you full control over each virtual machine. Youāll need this if youāre doing custom orchestration like rolling deploys across regions, temporary environments, or using fine-tuned scaling logic.
Weāll show you how both approaches work and help you figure out which one makes sense for your setup.
The easy way: flyctl + GitHub Actions
This is the path most Fly.io apps take, and itās what we recommend. You write code, you push to main, your app gets deployed. Itās quick to set up, and it abstracts away the VM lifecycle stuff unless and until you want it.
Hereās the gist:
- Get your app running on Fly.io
- Push the code to a GitHub repo
- Wire up a GitHub Actions workflow that calls
flyctl deploy
Step 1: Generate a deploy token
Step 2: Add it to your GitHub repo
In GitHub:- Go to your repo > Settings > Secrets and variables > Actions
- Add a new secret named
FLY_API_TOKEN - Paste in the deploy token
Step 3: Write the workflow file
Drop this into.github/workflows/fly.yml in your repo:
git push to main will kick off a deployment. You can watch it happen in the Actions tab.
The --remote-only flag tells flyctl to build your image on Fly.ioās remote builders, so your CI environment doesnāt need Docker.
From here on out, youāve got continuous deployment. Push to main, app goes live.
A realistic example: youāre running a Rails app backed by Postgres and Redis, deployed to iad and lhr. It lives in a monorepo, and you want each push to main to trigger a deployment. The flyctl + GitHub Actions setup gets you continuous deployment. Youāll handle the supporting infrastructure imperatively (think databases, IP addresses, scaling): fly pg create, fly redis create, fly scale count, fly ips allocate, and so on. The platform keeps track of what youāve configured, so you donāt need to re-declare it every time.
Tip: If you want a repeatable setup, you can script your commands into a bash file. Just be aware: that script will be linear and imperative, not declarative or idempotent like a Terraform plan.
The harder way: The Machines API
This is the route for teams who were doing more thanterraform apply. If you had logic layered into your infra automation like canary deploys, ephemeral environments, controlling exactly which VM runs where, youāll want to look at the Machines API. Itās lower-level, but more powerful. Think of it as Fly.ioās bare-metal interface. No plan, no state, no graph, just HTTP.
You can use it to:
- Spin up new Machines in specific regions
- Roll out changes a Machine at a time
- Build custom scaling logic
- Tear down and rebuild environments on demand
What youāre working with
The Machines API is a REST interface. It speaks JSON over HTTPS. You authenticate using a Fly.io API token, ideally a deploy token scoped to your app or organization. Pass it as aBearer token in the Authorization header. If youāve used GitHub Actions to deploy with flyctl, itās the same kind of token.
Each Fly App is a namespace. You can create as many Machines (VMs) as you want in an App. Each Machine runs a Docker image, has a region, some resource settings, and a lifecycle: create ā start ā stop ā destroy.
You donāt need special tooling to use it. curl works. So does fetch, requests, httpie, or whatever HTTP client you like in Go or Rust or Python. Everything you might script with flyctl, like creating databases, setting scale counts, can also be done via the Machines API. Itās more verbose, but gives you full control and makes it easier to integrate infrastructure setup into a larger orchestration flow.
Example: spin up a Machine with curl
/machines/{id} with the appropriate verb.
When to reach for the API
Most apps donāt need this. But if youāre building something dynamic, like spinning up short-lived browser-based dev environments or launching ephemeral multiplayer game servers, then youāll want this kind of control. Some of our favorite real-world uses:- A ārun this one function on a new machineā pattern, demoed in this JS repo. It boots a new Machine in-region, runs a job, and tears it down. Works like serverless, but with a full VM and no cold starts.
- A minimal Go client for the Machines API,
sosedoff/fly-machines, has helpers to create, update, and destroy Machines programmatically. If youāre replacing Terraform logic with your own Go-based orchestration, this is a good lightweight example. For something more comprehensive, check out our official fly Go SDK,superfly/fly-go, for tighter integration with the platform.
One last thing
We know it sucks when a tool you relied on gets deprecated. Terraform made a lot of things feel clean and declarative. But when it comes to the Machines API specifically, Terraform was always working at a bit of a mismatch since it tries to express an inherently imperative lifecycle in a declarative model. The Machines API gives you fine-grained control and flexibility that didnāt map cleanly to Terraformās abstractions. With a little effort, you can build exactly what you need, and avoid being boxed in by someone elseās idea of what an app should look like. If youāre rebuilding that tooling now, let us know what youāre working on. We might be able to help, or at least learn something from it.RelatedāÆReading
- Continuous Deployment with flyctl and GitHub Actions Walkāthrough on wiring CI/CD with Fly.io + GitHub Actions.
- Access Tokens for Fly.io Deep dive into token scopes, permissions, and best practices for automation workflows.
- Working with the Machines API Reference guide for automating at the VM/āmachineā level (the lowerālevel alternative to flyctl).
- App Configuration (
fly.toml) Details on how your app config file works, which is often part of your automation setup.