---
title: How to migrate from Fly.io to Vercel
description: Move an app from Fly.io to Vercel. Map configuration, choose Functions or Daemons, plan persistent storage, and verify the production cutover.
url: "https://vercel.com/kb/guide/migrate-fly-io-to-vercel"
published: 2026-08-11
last_updated: 2026-10-22
authors: Ben Sabic
related_resources:
  - title: "The Complete Guide to Vercel Services"
    url: "https://vercel.com/kb/guide/vercel-services"
    description: "Vercel Services let you deploy multiple frontends and backends in one project on a shared domain. Learn how to define services in vercel.json, route requests by path prefix, and connect services with generated environment variables."
  - title: "Running Docker on Vercel"
    url: "https://vercel.com/kb/guide/docker"
    description: "Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox."
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

To migrate an HTTP app from [Fly.io](http://Fly.io) to Vercel, copy your Dockerfile to `Dockerfile.vercel`, confirm the server listens on the port set by `PORT`, and deploy the repository to a Vercel project. Vercel [builds the image, stores it in Vercel Container Registry, and runs it as a function](https://vercel.com/kb/guide/does-vercel-support-docker-deployments) that scales with traffic.

Move application settings from `fly.toml` to environment variables and `vercel.json`, and keep persistent data in external backing services. Continuous workers use a separate Daemons configuration.

## Should your app move?

Separate HTTP traffic from processes that pull work continuously. Vercel Functions serve HTTP requests, while [Daemons](https://vercel.com/docs/daemons) run continuous workers from container images. Check each workload before moving it:

- Can it run without persistent local storage? Store uploads and durable session data in a backing service. Local caches can be temporary, but the app must remain correct when an instance disappears.
  
- Can the HTTP service tolerate scale-to-zero? Container Functions scale down after 5 minutes without traffic in production. If you use `min_machines_running` to keep a Fly Machine warm, test the application's startup behavior before migrating it.
  
- Do the Daemons beta limits fit your workers? Daemons maintain configured instance counts and run only in production. They currently have no autoscaling, preview execution, or inbound HTTP or TCP traffic.
  

For scheduled work, [Cron Jobs](https://vercel.com/docs/cron-jobs) call a production HTTP endpoint. [Queues](https://vercel.com/docs/queues) provide message delivery and retries, and [Workflows](https://vercel.com/docs/workflows) coordinate durable steps that can pause and resume. These models require changes to how the worker runs.

## How Fly.io concepts map to Vercel

| Fly.io                                       | Vercel                                                                                                                                            |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Dockerfile for an HTTP app                   | `Dockerfile.vercel` or `Containerfile.vercel`                                                                                                     |
| `internal_port` in `fly.toml`                | `PORT` environment variable in project settings, default 80, for container Functions                                                              |
| `fly deploy`                                 | `git push`, or `vercel deploy` from the CLI                                                                                                       |
| Fly.io image registry                        | [Vercel Container Registry](https://vercel.com/docs/container-registry) at `vcr.vercel.com`                                                       |
| Machines with `[[vm]]` sizing                | Function resource settings for HTTP workloads; Daemon resource settings and instance counts for workers                                           |
| `auto_stop_machines` / `auto_start_machines` | Container Functions scale in after 5 minutes idle in production, 30 seconds in preview; Daemons maintain configured counts                        |
| `kill_signal` / `kill_timeout`               | `SIGTERM`; container Functions allow 30 seconds, while Daemons have a configurable grace period                                                   |
| `fly secrets set`                            | Secret environment variables in project settings                                                                                                  |
| `[env]` in `fly.toml`                        | Environment variables in project settings                                                                                                         |
| Fly Volumes                                  | External storage: databases, caches, or blob storage                                                                                              |
| Multiple apps or process groups              | [Services](https://vercel.com/docs/services) for routed HTTP workloads, with explicit bindings for internal calls; Daemons for continuous workers |

## Steps

### 1\. Prepare the Dockerfile

Copy your existing `Dockerfile` to `Dockerfile.vercel` at the project root. The image contents follow standard OCI conventions, so most Dockerfiles need no changes; what matters is the port contract. Vercel routes traffic to the port in the `PORT` environment variable, which defaults to 80. On Fly.io, the port lives in `fly.toml` as `internal_port`, and the app itself often hardcodes it.

If your server already reads `PORT` from the environment, as most Fly.io apps do, nothing changes. If it hardcodes a port, you have two options: update the code to read `PORT`, or set `PORT` in your Vercel project settings to the port the server listens on. Don't rely on an `ENV PORT` line in the Dockerfile to change where traffic routes; the routed port comes from project settings, not the image.

### 2\. Create the Vercel project and deploy

Import the repository into a Vercel project and configure the environment variables and backing services described in the next two steps before deploying. Vercel detects `Dockerfile.vercel`, builds the image, and pushes it to Vercel Container Registry. Container Functions run on Fluid compute with [Active CPU pricing](https://vercel.com/blog/dockerfile-on-vercel), alongside Provisioned Memory and invocation usage.

The first deployment of a new project is a production deployment, even when requested as a preview. Use test backing services for the initial validation, and leave worker instance counts at zero until you are ready to transfer work from [Fly.io](http://Fly.io).

After the first deployment, commits to a non-production branch create preview deployments by default. If the frontend and API are configured as Services in the same project, they deploy together. Give previews separate credentials for test databases and other backing services; a preview URL does not isolate those resources. Daemons do not run in previews during the beta.

### 3\. Move configuration and secrets

Copy application settings from `[env]` in `fly.toml` into your Vercel project's environment variables, and recreate credentials set with `fly secrets set` as **Secret** variables. Secret values are write-only after saving.

Assign each value to the intended environment. Keep existing variable names where the application expects them, and update values such as database endpoints for the destination services. The container receives these variables.

Vercel does not read platform settings from `fly.toml`. For HTTP Functions, review the Function configuration instead of copying `auto_stop_machines`, `force_https`, or `[[vm]]` blocks. Set Daemon regions, instance counts, and resources in `vercel.json`.

### 4\. Move state out of the container

Fly Volumes provide persistent storage attached to Machines. Vercel Functions and Daemons need external storage for data that must survive instance replacement. Instances may reuse temporary state across requests until replacement.

- For Fly Postgres or another database on a Machine, choose whether to retain the database with a verified connection path or migrate its data to a managed database, such as one from the Vercel Marketplace. Set the destination connection string as an environment variable.
  
- Move uploaded files on volumes to blob storage and update the code that reads and writes them.
  
- Put shared sessions and caches that must survive restarts in a managed store such as Redis. Keep disposable local caches only if the app handles cache misses correctly.
  

Changing a connection string does not copy existing data. Before switching writes, rehearse the database export and restore or the provider's migration process, verify the result, and account for writes that arrive after the initial copy. Before cutover, pause writes or synchronize them through a tested process.

If you retain an existing backing service, verify connectivity from Vercel, including authentication and TLS. Fly.io's `.internal` addresses only work within its private network, so copying those values won't connect Vercel to the service.

### 5\. Consolidate multiple apps into services

If your frontend and API are in the same repository, define them under `services` in `vercel.json`. Set each service's `root`, then set its `runtime` to `container` and its `entrypoint` to the Dockerfile path relative to that root. Top-level rewrites expose the services that should receive public traffic.

For private calls between services, declare a [binding](https://vercel.com/docs/services/bindings) on the calling service. The binding names the target and the environment variable that receives its generated URL. Services deploy together and run locally with `vercel dev`.

Map continuous Fly.io process groups to `daemons` alongside `services`. Preserve any startup command from `[processes]` in `fly.toml`; copying the Dockerfile alone can restore its default command. Container service `command` overrides the image's `CMD`, while Daemon `command` replaces both `ENTRYPOINT` and `CMD`. Check entrypoint scripts before translating those commands.

### 6\. Migrate images you want to keep

Deploys build fresh images from `Dockerfile.vercel`, so most teams don't need to move old images at all. If you keep release images for rollback or compliance, copy them into VCR with standard Docker tooling; the commands in the [GHCR migration guide](https://vercel.com/kb/guide/migrate-ghcr-to-vcr) work against any OCI registry, including Fly.io's. Run `fly auth docker` first to authenticate Docker with Fly.io's registry, then `docker buildx imagetools create` copies multi-platform images without pulling layers locally.

### 7\. Verify and cut over

Test the HTTP app through its Vercel deployment URL with isolated backing services. If you need a production-data check, use credentials that enforce read-only access. Validate production settings before routing customer traffic.

Add the custom domain to the Vercel project, then update the website's DNS records to the values shown in **Settings > Domains**. Verify the domain and certificate status as traffic moves. Keep the Fly.io app available through the rollback window and verify access to the authoritative database.

Move workers separately from HTTP traffic. Coordinate the Fly.io consumers and Vercel Daemons so pending work has an owner and retries cannot repeat harmful side effects. Retire the old app only after its HTTP traffic and background work have moved and the retained data is accounted for.

Use `vercel dev` with the Docker CLI and daemon to investigate the HTTP containers locally. Test Daemon images separately with Docker; they do not run in `vercel dev` or preview deployments during the beta.

## What doesn't map from Fly.io

- Volumes. There is no attached persistent disk for Functions or Daemons. Move data that must survive instance replacement to external storage.
  
- Worker deployment behavior. Continuous workers can run as Daemons, but the beta does not support previews or autoscaling. Keep workers on Fly.io if those limits prevent the migration.
  
- `release_command`. Move the migration command into a coordinated CI or deployment-pipeline step that can reach the intended database. Stop the release if it fails, and keep schema changes compatible with the Fly.io app while that app remains a rollback target.
  
- Shutdown behavior. Container Functions receive `SIGTERM` with a fixed 30-second grace period. Daemons default to 30 seconds and allow `terminationGracePeriodSeconds` to extend it up to 3,600 seconds. Test how each process finishes or returns unfinished work before stopping.
  
- Egress requirements. Secure Compute and Static IPs are not supported by Functions running custom container images. Verify a compatible connection path before moving an app whose dependencies require allowlisted outbound IPs.
  

## Frequently asked questions

### Can I reuse my Fly.io Dockerfile on Vercel?

For an HTTP app, you can usually reuse it by copying it to `Dockerfile.vercel` and matching the server's listening port to the project's `PORT` value. Both platforms use OCI images, but startup commands supplied through Fly.io's `[processes]` configuration must also be carried over. Continuous workers use a Daemons configuration instead of the HTTP Function path.

### What replaces auto\_stop\_machines and auto\_start\_machines?

For HTTP container Functions, Vercel manages scaling automatically. Instances scale down after five minutes without production traffic and start again when requests arrive, using optimized boot images that reduce startup work. Daemons keep the instance counts you configure and do not autoscale during the beta.

### Does Vercel have an equivalent of Fly Volumes?

No. Containers on Vercel are stateless, so persistent data lives in external services: a managed database, cache, or blob storage. Anything the app writes to local disk exists only for the life of that instance.

### How does pricing differ from paying for Machines?

HTTP containers use the Vercel Functions billing model, which measures Active CPU, Provisioned Memory, and invocations. Waiting for I/O does not consume Active CPU, but memory billing continues while requests are in progress.

Daemons have separate quotas and charge for Active CPU and Provisioned Memory usage on Pro and Enterprise.

### Can I migrate gradually?

Yes. Test the HTTP app on a Vercel deployment URL, then use a rewrite or reverse proxy to move selected routes while the remaining traffic stays on [Fly.io](http://Fly.io). Keep backing services consistent across both apps and use separate test resources for preview deployments. Transfer background-worker ownership separately, since Daemons do not execute in previews.

## Related resources

- Migrate to Vercel from [Railway](https://vercel.com/kb/guide/migrate-railway-to-vercel), [Render](https://vercel.com/kb/guide/migrate-render-to-vercel), or [Google Cloud Run](https://vercel.com/kb/guide/migrate-cloud-run-to-vercel)
  
- [Does Vercel support Docker deployments?](https://vercel.com/kb/guide/does-vercel-support-docker-deployments) and [How to migrate from GHCR to Vercel Container Registry](https://vercel.com/kb/guide/migrate-ghcr-to-vcr) guides
  
- [Run any Dockerfile on Vercel](https://vercel.com/blog/dockerfile-on-vercel) on the Vercel blog
  
- [Container images](https://vercel.com/docs/functions/container-images) and [Vercel Container Registry](https://vercel.com/docs/container-registry) in the Vercel Docs
  
- [7 ways to use Docker containers on Vercel](https://vercel.com/i/7-ways-to-use-docker-containers-on-vercel)

## Related Resources

- [The Complete Guide to Vercel Services](https://vercel.com/kb/guide/vercel-services): Vercel Services let you deploy multiple frontends and backends in one project on a shared domain. Learn how to define services in vercel.json, route requests by path prefix, and connect services with generated environment variables.
- [Running Docker on Vercel](https://vercel.com/kb/guide/docker): Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox.

## More Vercel Services guides

- [How to migrate from Google Cloud Run to Vercel](/kb/guide/migrate-cloud-run-to-vercel): Move a Cloud Run service or worker to Vercel. Compare runtimes, preserve Google Cloud access, and plan jobs, validation, and production cutover.
- [How to use Vercel Container Registry](/kb/guide/how-to-use-vercel-container-registry): Push, store, and pull OCI container images with Vercel Container Registry, then deploy them to Vercel Functions and Vercel Sandbox.
- [Running Docker on Vercel](/kb/guide/docker): Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox.