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

  1. 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.
  2. 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 Secret field.
      • Click Add secret.
    • 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.
  3. GitHub Actions Workflow File: Create or modify a .github/workflows/deploy.yml file 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 the flyctl CLI on the GitHub Actions runner. This makes the flyctl command 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 the flyctl CLI on the runner with your Fly.io account.

    • flyctl deploy --remote-only --app my-cool-app: This is the core deployment command. --remote-only tells flyctl to 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-app specifies which Fly.io application you are deploying to. You must replace my-cool-app with 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 the flyctl commands, 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.

Want structured learning?

Take the full Fly-io course →