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 afly.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_URLis 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 concept | PandaStack equivalent |
|---|---|
[build] / Dockerfile | Dockerfile build (auto-detected) |
[http_service] internal_port | Service port |
[env] | Env vars |
[[services]] / ports | Service / routing config |
[mounts] (volumes) | Persistent storage / managed DB |
fly secrets | Env 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 = 8080Translate 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 shownFly 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.
- 1Provision a PandaStack PostgreSQL (14.x or 16.x).
- 2Dump from Fly. Connect via
fly proxyto 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- 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
- 1Push your repo; let PandaStack build and deploy to a staging domain.
- 2Smoke-test every endpoint and background process.
- 3Do a final database delta (a fresh dump/restore during a short maintenance window, or logical replication if you need zero-downtime).
- 4Switch DNS to PandaStack; SSL auto-provisions.
- 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).