GitHub Actions can deploy directly to Fly.io, but it’s not a simple fly deploy from your workflow.
Here’s a Fly.io app running:
$ flyctl apps list
App Name | Owner | Status
---------|-------|--------
my-cool-app | my-org | running
And here’s a request being served:
$ curl -H "Host: my-cool-app.fly.dev" http://localhost:3000
Hello from Fly.io!
To make this happen, you need to set up your GitHub Actions workflow to authenticate with Fly.io and then issue the necessary commands.
The Setup
-
Fly.io API Token: You need an API token from Fly.io to authenticate your GitHub Actions runner.
- How to get it:
- Go to your Fly.io account settings: https://fly.io/user/edit
- Scroll down to the "API Tokens" section.
- Click "Create new token".
- Give it a descriptive name, like
github-actions-deploy. - Copy the generated token immediately. You won’t be able to see it again.
- Why it works: This token acts like a password for your GitHub Actions runner to prove its identity to Fly.io, allowing it to manage your deployed applications.
- How to get it:
-
GitHub Secrets: Store your Fly.io API token securely in your GitHub repository.
- How to set it up:
- In your GitHub repository, go to
Settings>Secrets and variables>Actions. - Click
New repository secret. - Name the secret
FLY_API_TOKEN. - Paste your Fly.io API token into the
Secretfield. - Click
Add secret.
- In your GitHub repository, go to
- Why it works: Storing sensitive credentials like API tokens in GitHub Secrets prevents them from being exposed directly in your workflow files, which are often version-controlled and visible.
- How to set it up:
-
GitHub Actions Workflow File: Create or modify a
.github/workflows/deploy.ymlfile in your repository.name: Deploy to Fly.io on: push: branches: - main # Or your primary branch jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Flyctl uses: superfly/flyctl-actions/setup-flyctl@master - name: Log in to Fly.io env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} run: flyctl auth login --fly-api-token $FLY_API_TOKEN - name: Deploy to Fly.io run: | flyctl deploy --remote-only --app my-cool-app env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}-
uses: superfly/flyctl-actions/setup-flyctl@master: This action downloads and installs theflyctlCLI on the GitHub Actions runner. This makes theflyctlcommand available for subsequent steps. -
flyctl auth login --fly-api-token $FLY_API_TOKEN: This command uses the API token stored in your GitHub Secrets to authenticate theflyctlCLI on the runner with your Fly.io account. -
flyctl deploy --remote-only --app my-cool-app: This is the core deployment command.--remote-onlytellsflyctlto build the Docker image on Fly.io’s infrastructure rather than locally on the runner, which is faster and more reliable for CI/CD.--app my-cool-appspecifies which Fly.io application you are deploying to. You must replacemy-cool-appwith the actual name of your Fly.io application. -
env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}: This makes your secret token available as an environment variable within theflyctlcommands, allowing them to authenticate.
-
The Internal Mechanics
When flyctl deploy runs, it packages your application’s code and its Dockerfile (if present) or uses a language-specific builder. It then pushes this package to Fly.io’s build infrastructure. Fly.io builds your Docker image in their cloud, and once that’s complete, it deploys the new image to your application’s running instances, replacing the old version. The --remote-only flag is crucial here; without it, flyctl would attempt to build the Docker image on the GitHub Actions runner itself, which is often slower and can lead to environment inconsistencies. The flyctl auth login step establishes a secure, temporary session for the flyctl CLI on the runner, allowing it to communicate with the Fly.io API to initiate and manage the deployment process.
The next thing you’ll likely want to configure is how your application scales based on traffic.