Migrate an Existing Fly App to V2

All new apps on the Fly Platform are V2 Apps, running on Fly Machines. Our docs apply to V2 Apps, but we still include legacy V1 Apps info where appropriate.

We’re migrating all V1 Apps to V2 in phases. Learn more about how and why we’re getting off Nomad.

You can also migrate your V1 app yourself using our migration and migration troubleshooting tools, or migrate your V1 app manually.

Migrate a V1 App with a flyctl command

flyctl includes a command you can run yourself to migrate an existing V1 App to a V2 App. Find more detail and discussion in our community forum.

  1. Make sure you’re running the latest flyctl, with fly version upgrade (or brew update && brew upgrade flyctl on macOS).
  2. Enter your Fly App’s source directory. If you don’t already have one for this app, create a new directory first; the migration command saves the updated configuration into fly.toml locally.
  3. Save a backup copy of the app’s old fly.toml if there is one.
  4. Run fly migrate-to-v2 -c ./fly.toml.

Read this if your app uses volume storage

If your app uses Fly Volumes for persistent storage, migration will cause a brief downtime while fly migrate-to-v2 clones the volume contents onto new volumes. VMs are shut down before the copying starts, for data-integrity reasons.

fly migrate-to-v2 does not delete the original volumes, out of an abundance of caution. We leave this for you to do once you are certain the migration has succeeded with the volume data intact. The active volumes have the original volume names, but with -machines appended—keep those ones!

Troubleshoot your app migration

If your app is in an incorrect state post-migration, you can run the troubleshoot sub-command:

fly migrate-to-v2 troubleshoot

This command will try to automatically repair common issues with your app. If there is any ambiguity as to what to do (such as an app in the detached state), it will drop you into an interactive repair wizard that helps you make the right decisions.

Find out more about the self-service troubleshooting tool in our community forum.

Migrate a V1 App manually

If you’d rather work through the process manually, here are some steps to convert a fairly simple existing legacy V1 App (managed by Nomad) to a V2 App (running on Fly Machines).

The idea is to get the new app up and running satisfactorily, keeping your old one running until you’re comfortable to migrate DNS to the new Machines-based app.

Create a new V2 app

fly apps create --name <my-app-v2> -o <my-org>

Put the new app name into the fly.toml config file

Edit fly.toml in place, or make a duplicate of your app’s source directory to use for the new app.

Replace the app name with the new app name. If your new app is literally called my-app-v2, that line looks like this:

app = "my-app-v2"

Set the app’s primary region

Still in fly.toml, add a primary_region option, which fly deploy in uses to determine where to create new Machines in V2 Apps, as well as to set the PRIMARY_REGION environment variable within the Machines it deploys. Replace ord with the three-letter code for your Fly Region of choice.

primary_region = "ord"

Note: V2 Apps don’t use region groups or fly regions commands. You can use fly scale count --region or fly machine clone --region to create Machines in specific regions.

​Copy any secrets you need from your existing app

Find out which secrets you need to recreate with

fly secrets list -a <my-old-app>

A quick way to see those secrets is

fly ssh console -C env -a <my-old-app>

Set secrets on the new app to match with fly secrets set. For example:

fly secrets set DATABASE_URL=<database-url-from-old-app> REDIS_URL=<redis-url-from-old-app>

in the new app’s working directory.

Here’s a shell script to combine the above steps, using the ability of fly secrets import to import key=value pairs from stdin:

# Clone secrets from one Fly app to another

trap "rm -rf $TEMPFILE" EXIT

SECRET_KEYS=`fly secrets list -a $1 | tail -n +2 | cut -f1 -d" "`
fly ssh console -a $1 -C env | tr -d '\r' > $TEMPFILE

for key in $SECRET_KEYS; do

grep $PATTERN $TEMPFILE | fly secrets import -a $2

A note on Fly Volumes

If your app uses Fly Volumes, you’ll have to provision a volume for the first Machine to be deployed. Volumes cannot be transferred between apps; you may need to copy data down from the old app, or create the new volume from a snapshot.

Horizontal scaling of Machines that have volumes is done using fly m clone, which will provision a new volume for the new Machine but will not copy any data into it; it’s up to your app to do data replication between instances, if needed.

Deploy your new V2 app

fly deploy

If the app has HTTP/HTTPS services configured on standard ports, the first deployment will provision a dedicated public IPv6 and a shared public IPv4 address for it.

Check that your app is running correctly:

fly status

More ways to get info about an app, its Machines, and its status

Make sure the Machines’ Restart Policy Suits Your App

Fly Machines have a restart policy as part of their configuration, determining whether the Machine should restart when its main process exits, or just enter the stopped state.

There are three possible policies: no, always, and on-fail.

The default policy configured by fly deploy is equivalent to on-fail: flyd will try restarting a Machine up to 10 times if it exits with a non-zero exit code.

There is a temporary gotcha with this policy, however: right now, when a host reboots, this is not recognised as a failure, and so Machines enter the stopped state when the host comes up, instead of being restarted. Machines with services configured will tend to be woken by Fly Proxy in the course of its load-balancing activities, but Machines without services will stay stopped until you start them.

We recommend updating such Machines to use the always restart policy, to ensure that they come back up after a host reboot:

fly machine update --restart always <machine-id>

Learn more about Machine restart policies.

Scale your deployed Machine(s)

First deployment spins up a Machine with a single shared CPU core and 256MB RAM. If your app needs more oomph, scale it with fly m update.

Scale out

For a production app, you should have at least two VMs provisioned for each process. Unlike Nomad, flyd does not attempt to move VMs if their host hardware fails. Having VMs in multiple regions improves availability in the case of regional outages. Databases likely want redundancy within a region for failover purposes.

To scale your app horizontally, you can clone an existing VM:

fly m clone --select

If you need to deploy in another region, also clone, but into another region:

fly m clone --select --region ams

Add and check certs; switch DNS

If you have domains/certs attached to your app, you’ll want to add them here again:

fly certs add <my-custom-domain.com>

The output will show you the IP allocated for your app, or you can use fly ips list.

Check that any certificates have been issued:

fly certs check
dig txt _acme-challenge.mydomain.com +short

Finally, point your DNS to the new IP allocated for your app.

Delete the old V1 App

Once you’ve switched over to the new V2 App and you’re confident you don’t need the V1 app anymore, delete it.

Adopt standalone Fly Machines into a V2 App

Fly Launch allows you to manage Fly Machines with app-wide configuration and coordinated releases, using fly launch and fly deploy. If you have a non-V2-Apps Machine app—created using fly create --machines or fly machine run—you may or may not want to migrate it to a V2 App in order to gain fly deploy functionality.

This is an important point: Fly Launch (through the fly launch and fly deploy commands) unifies all the Machines it manages to use a single Docker image and a single configuration. As an example, the services and environment variables will come from fly.toml on the next deployment, replacing whatever was present before.

Thus, migrating an older “Machines” Fly App to Fly Launch is fairly straightforward if all the Machines belonging to the app are running the same image with the same configuration.

From your project’s source directory (where you’ll be deploying it from, and where fly.toml should live):

$ fly config save -a appname # to get a fly.toml from a machine's config
$ fly machine update --metadata fly_platform_version=v2 9080eee5a1d518 # do this for each machine 
$ fly deploy

For an app with Machines running different images, it’s more awkward. There’s a good chance you’d be better off starting with a fresh V2 app, and adding any special Machines with fly machine run after it’s deployed.

fly config save doesn’t expect there to be a difference between Machines, so it’s not currently possible to select a specific Machine to pull a new app config from. In this case, the process would look more like:

  • get or create a fly.toml file to match the config you want fly deploy to apply to its Machines
  • run fly machine update --metadata fly_platform_version=v2 <machine-id> only on any Machines that you want fly deploy to manage.
  • fly deploy

This deployment now updates the adopted Machines with the app-wide image and configuration.