Back to Blog
Tutorial10 min read2026-07-06

How to Migrate from Fly.io to PandaStack

Migrate your Fly.io apps from fly.toml and Dockerfiles to PandaStack: translating config, moving Postgres data, handling volumes and secrets, and the architectural differences to plan around.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Fly.io runs your Docker containers close to users on its own orchestration platform, with a strong CLI-first workflow. If you're moving to PandaStack, you're typically after a managed Git-push experience, managed databases that auto-wire into your app, and an integrated dashboard. This guide translates Fly concepts to PandaStack and walks the data migration.

Architectural differences to plan around

Before touching config, understand what's different:

  • Deploy model. Fly is CLI-driven (fly deploy) from a fly.toml. PandaStack is Git-push driven: connect a repo, push, it builds and deploys.
  • Build. Fly builds via your Dockerfile (remote or local builder). PandaStack builds your Dockerfile with rootless BuildKit in an ephemeral Kubernetes Job pod, pushing to Google Artifact Registry, then deploys via Helm — no host Docker socket.
  • Database. Fly Postgres is (historically) an app you manage yourself on Fly. PandaStack databases are fully managed (via KubeBlocks) with scheduled and manual backups, and DATABASE_URL is injected automatically.
  • Regions. Fly emphasizes per-app multi-region placement. PandaStack runs multi-region GKE with Kong ingress and Cloudflare DNS.

Config mapping

fly.toml conceptPandaStack equivalent
[build] / DockerfileDockerfile build (auto-detected)
[http_service] internal_portService port
[env]Env vars
[[services]] / portsService / routing config
[mounts] (volumes)Persistent storage / managed DB
fly secretsEnv vars (secret)
[processes]Separate services or process config

Step 1: Reuse your Dockerfile

The best news: if you deploy on Fly with a Dockerfile, that same Dockerfile generally works on PandaStack unchanged. One thing to verify — rootless builds. PandaStack builds rootless, so any step that strictly requires root at *build* time needs adjustment. Most Dockerfiles are fine; watch for things like installing packages that assume root in odd ways, or USER directives that the build assumes.

If you don't have a Dockerfile and relied on Fly's buildpacks, PandaStack can auto-detect buildpacks for Node/Python/Go and more.

Step 2: Translate fly.toml

Walk through your fly.toml:

# fly.toml (excerpt)
app = "myapp"

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "8080"
  LOG_LEVEL = "info"

[http_service]
  internal_port = 8080

Translate this to: a connected repo with the Dockerfile, a service port of 8080, and env vars LOG_LEVEL=info (PandaStack provides the port via the service config). Make sure your app reads the port from the environment.

Step 3: Move secrets

List your Fly secrets and recreate them as env vars in PandaStack:

fly secrets list   # names only; values aren't shown

Fly doesn't display secret values, so you'll need them from your own records (or rotate them during migration — a good habit anyway). Add each as a secret env var on the PandaStack service.

Step 4: Migrate the database

If you ran Fly Postgres, dump and restore into a PandaStack managed PostgreSQL.

  1. 1Provision a PandaStack PostgreSQL (14.x or 16.x).
  2. 2Dump from Fly. Connect via fly proxy to reach the database locally:
# Forward Fly Postgres to localhost
fly proxy 5432 -a my-postgres-app &

# Dump
pg_dump "postgres://user:pass@localhost:5432/mydb" -Fc -f mydb.dump
  1. 1Restore into PandaStack:
pg_restore --no-owner --no-acl -d "$PANDASTACK_DATABASE_URL" mydb.dump

--no-owner --no-acl avoids importing Fly-specific role/ownership metadata. Match the major version where possible (dump on 16, restore on 16) to avoid surprises.

Once attached, PandaStack injects DATABASE_URL into your app automatically — drop your hardcoded Fly connection string.

Step 5: Handle volumes

Fly volumes back stateful apps. Inventory what's on them:

  • Database data → moved already via dump/restore.
  • User uploads / generated files → move to object storage if at all possible; object storage is far more portable and survives redeploys cleanly.
  • Truly local state → use persistent storage, but reconsider whether the state should live in the database or object storage instead. Stateless containers are easier to scale and migrate.

Copy volume contents out with fly ssh sftp or a one-off job before tearing anything down.

Step 6: Multi-region considerations

If you ran Fly across regions, decide what you actually need. Many apps run multi-region for latency but keep a single primary database — which means cross-region writes already traverse to one region. PandaStack runs on multi-region GKE; design your topology around where your database lives and where your users are. (Our multi-region architecture guide covers the trade-offs in depth.)

Step 7: Cutover

  1. 1Push your repo; let PandaStack build and deploy to a staging domain.
  2. 2Smoke-test every endpoint and background process.
  3. 3Do a final database delta (a fresh dump/restore during a short maintenance window, or logical replication if you need zero-downtime).
  4. 4Switch DNS to PandaStack; SSL auto-provisions.
  5. 5Keep Fly running briefly for rollback.

Checklist

  • [ ] Dockerfile verified rootless-safe
  • [ ] fly.toml translated (port, env, processes)
  • [ ] Secrets recreated (and ideally rotated)
  • [ ] Postgres dumped and restored; counts verified
  • [ ] Volumes triaged (DB / object storage / persistent)
  • [ ] Region topology decided
  • [ ] Staging tested, DNS cutover planned

References

  • [Fly.io app configuration (fly.toml)](https://fly.io/docs/reference/configuration/)
  • [Fly.io secrets](https://fly.io/docs/apps/secrets/)
  • [PostgreSQL pg_dump / pg_restore](https://www.postgresql.org/docs/current/app-pgdump.html)
  • [BuildKit rootless mode](https://github.com/moby/buildkit/blob/master/docs/rootless.md)
  • [KubeBlocks](https://kubeblocks.io/)

---

If you already containerize on Fly, you're 80% of the way to PandaStack — same Dockerfile, plus a managed database that wires itself in. Try the free tier (5 web services, 1 database) at [dashboard.pandastack.io](https://dashboard.pandastack.io).

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also