
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.