Managing multiple environments

Not yet! I’ve started just having fly.kurt.yml file variants, but I still have to -f <file> on every command.

1 Like

I have two environments, dev and prod. They both share the same yml file, but I have removed the name from the toml file.

I have setup a github workflow, where pushes to development branch get deployed with fly deploy -a dev and pushes to master branch get deployed with fly deploy -a prod


What is the long-term goal here? Because it can’t be uncommon to want to have multiple deployments for one app?

I could see something like having one app but with multiple “channels” for deployment, where you can override specifics for that given channel. Also, untangling domains and such from a specific app would be nice as well but it may already be so I’ll have to investigate this further soon. I have an API and a separate Angular app which would have to be deployed as separate apps so as to not have to merge these projects into one app, but they will use the same domain and same wildcard certificate, I am hoping.

The long term goal is to figure out a good UX for one app config → multiple apps.

We haven’t quite decided how to route one domain to multiple apps yet, and I expect it’ll be a while before we do. But we do have a neat statics feature you can use for backend/static app deployment. It should be pretty easy to build statics into an API image, and you wouldn’t need to add any other webservers (since we handle that).

1 Like

I’m just wondering why an app must only have one deployment, as that seems to be the core idea of :thinking: In my experience that’s rarely the case with medium-bigger projects so I’m wondering.

It’s not really the core idea, just the simplest thing to build from scratch. I actually create multiple versions of most of my apps. :slight_smile:

Our goal, so far, has been to make fly deploy just work for most apps. Things like deploy pipelines and multiple environment support are really useful for people who already like Fly, but somewhat complex for tire kickers. The good news is, there are a lot of people who really like using us now, so it makes sense to start building more powerful features.


Could you share your yml file that configures the github action?

This seems like a good time to pitch environment-specific binstubs:

bin/production contains FLY_APP=app exec flycli $@ while bin/staging contains FLY_APP=app-staging exec flycli $@. instead of calling fly directly, you call the environment specific binaries that are checked in to your repo. imo, it’s still more ergonomic than Heroku’s pipelines, and it’s usable with far less server side rolling around it.


I liked how heroku did pipelines when managing dev → staging → prod.

Configure 3 apps, each with their own configurations (vn size, dyno counts, env, etc)

Setup branches per app, and then also allow for manual propagation.

1 Like

I just got started with Fly and have multiple environments for my app. Here how I do it…

I have a separate config file for each environment. E.g. fly.staging.toml,

In my CI I just declare the config file to use when deploying.

e.g. fly deploy -c fly.staging.toml -i <image-name>

1 Like

This is how I currently achieve this as well.

I don’t have the app name in fly.toml

# fly.toml file generated for indiepaper-dev on 2021-09-02T14:43:54+05:30
kill_signal = "SIGTERM"
kill_timeout = 5



I specify that in Github Workflow that is separate for Development and Production.

name: Deploy develop branch to indiepaper-development on fly
      - develop
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
    name: Deploy Development App
    runs-on: ubuntu-latest
      - uses: actions/checkout@v2
      - uses: superfly/flyctl-actions@master
          args: "deploy -a indiepaper-development --remote-only"

For production change the name to indiepaper-production

This way you only need to maintain one fly.toml, but whenever you are running locally you need to specify the app with fly status -a indiepaper-development.


Makes sense. I have this setup with several apps now and it works great.

One way i’ve done in the past is to generate the fly.toml on the fly (pun or no pun intended… never understood which one to choose) on the CI/CD pipeline.

You can do an echo "config template" > fly.toml and generate/populate the config with the data u need, and then call fly deploy -c fly.toml

this way you never have to worry about stage or prod envs on your local environment.

And if you actually want to do it properly just use, and you never have to worry about .envs anymore in your life.


There’s great content here. I will leave here also how we do it (similar to @aswinmohanme):

  name: Build and deploy
  runs-on: ubuntu-latest
    # (...)
    - uses: actions/checkout@v2

    - uses: superfly/flyctl-actions/setup-flyctl@master
    - run: flyctl -a our-app-staging deploy --remote-only
      if: github.ref == 'refs/heads/develop'
        FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

    - run: flyctl -a our-app-production deploy --remote-only
      if: github.ref == 'refs/heads/main'
        FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

Locally there’s a handy env var FLY_APP (ex: export FLY_APP=our-app-name) , you could also pass -a our-app-name on every fly command or

1 Like

I like the idea of having the two scripts. But I was also thinking having something akin to the Heroku piplines could be nice.

A caveat: This -a <staging-or-prod> trick doesn’t work with Machine apps (yet): Preview: Deploying applications on Machines with flyctl - #6 by ignoramous

Well, “pipelines” seems to be on Fly’s roadmap anti-roadmap: Rough edges for multi-app services - #2 by kurt

I keep the app name in the fly toml the staging app, and when I want to deploy production I promote the latest staging image to production, so I never build a new image for production, simply deploy one of staging’s images:

#!/usr/bin/env ruby
require "json"

js = JSON.parse(`flyctl image show --json`)
registry = js["Registry"]
tag = js["Tag"]
repo = js["Repository"]
production_app = "app-production"

cmd = "flyctl deploy -i #{registry}/#{repo}@#{tag} -a #{production_app}"
puts "----> Running #{cmd}"
1 Like

Ah, similar to: Deploy fly apps using custom made bot - #3 by kurt

This works because I guess you must have already deployed the required config (aka fly.toml) to prod at least once?

Sharing my solution here.

I have two apps deployed: and

Make sure you create them running: flyctl deploy -a <appn_ame>.

The toml file does not have an app name and my gh workflow is this:

➜ cat .github/workflows/fly.yml
name: Fly Deploy Prod
      - main
      - dev
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
    name: Deploy app
    runs-on: ubuntu-latest
      - uses: actions/checkout@v3
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - name: run_flyctl
        run: |
          echo "github.ref is: ${{github.ref}}"
          if [[ "${{github.ref}}" == "refs/heads/main" ]]; then
            echo "deploying to PROD"
            flyctl deploy --remote-only -a drio-fly
          if [[ "${{github.ref}}" == "refs/heads/dev" ]]; then
            echo "deploying to DEV"
            flyctl deploy --remote-only -a drio-fly-dev
1 Like