Fly.io Migration Guide: Move to HostStack
Move a Fly.io app to an EU company on EU infrastructure: fly.toml to hoststack.yaml, secrets, release_command and Postgres, in about an hour.
Fly.io gives you machines in 17 regions — five of them in Europe — and lets you build the platform on top. It is also a US company: Fly.io, Inc., under California law, so an Amsterdam or Frankfurt region does not change who can be compelled to hand data over. New organisations have had no free allowance since Fly retired its plans in October 2024, and Fly Managed Postgres starts at $38/mo plus storage. HostStack is the opposite trade: one EU region, an opinionated PaaS, and the database, backups, cron and workers run for you.
Why switch from Fly.io?
- An EU company on the contract: HostStack is operated by MICCI, a Danish company, with every service and database in Helsinki. Fly.io, Inc. is a US company, so the US CLOUD Act reaches it in every region it runs.
- Managed Postgres from €4/mo with storage and nightly backups included, and in-place major-version upgrades from the CLI or dashboard. Fly Managed Postgres starts at $38/mo plus $0.28/GB of storage, and Fly lists security patches and version upgrades as not there yet.
- A free tier that does not expire: 1 Nano service + 1 Starter Postgres + 1 cron + 1 preview env, no card. A new Fly organisation gets a trial of up to 2 machine-hours or 7 days, and needs a card on file.
- Deploys on every push from GitHub, GitLab, Bitbucket or Codeberg, with no CI workflow of your own to write.
- Managed MySQL, MariaDB, MongoDB and Redis next to Postgres on the same bill. On Fly, Redis is Upstash.
- No Dockerfile required: HostStack detects Node, Bun, Python, Ruby, Go, Rust, Java, PHP, .NET and Elixir and builds them itself — or builds the Dockerfile you already deploy to Fly.
- 200 GB/team of bandwidth included, then a flat 1¢/GB, invoiced in EUR with EU VAT.
Price comparison
| Resource | Fly.io | HostStack | Comparison |
|---|---|---|---|
| Free allowance | None for new organisations (trial: 2 machine-hours or 7 days) | Nano service + Starter Postgres, no time limit | Free vs trial |
| 1 GB always-on service, EU | $7.73/mo shared-cpu-1x 1 GB (Frankfurt) | €10/mo Small (1 GB, Helsinki) | Fly cheaper on raw compute |
| Cheapest managed Postgres | $38/mo Basic (1 GB RAM, with replica) + $0.28/GB storage | €4/mo Micro, storage included | ~90% |
| Bandwidth (100 GB egress, EU) | $2 ($0.02/GB) | €0 (inside the 200 GB/team allowance) | 100% |
| Volume (10 GB) | $1.50/mo ($0.15/GB, billed while the machine is stopped) | €1/mo (10¢/GB·mo) | ~33% |
Fly.io prices checked October 2026 against their public pricing page. Fly.io prices are USD as published; HostStack figures are the live EUR catalog. Verify at the source before deciding.
Code migration
Before (Fly.io)
# fly.toml
app = "my-app"
primary_region = "ams"
[build]
dockerfile = "Dockerfile"
[env]
NODE_ENV = "production"
[deploy]
release_command = "npm run migrate"
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = "stop"
auto_start_machines = true
min_machines_running = 0
[[mounts]]
source = "data"
destination = "/data"After (HostStack)
# hoststack.yaml -- configures the existing "my-app" service
services:
my-app:
port: 3000
env:
NODE_ENV: production
disk:
name: data
mountPath: /data
sizeGB: 1
# Not in this file -- set on the service:
# [build] dockerfile -> hoststack services update svc_... --dockerfile-path Dockerfile
# release_command -> hoststack services update svc_... --pre-deploy-command "npm run migrate"
# Postgres -> hoststack db create --project prj_... --name my-db --engine postgres --plan micro
# hoststack db link db_... --service svc_...Feature comparison
| Feature | Fly.io | HostStack |
|---|---|---|
| Deploy trigger | fly deploy from flyctl | Every push, or hoststack deploy trigger |
| Build | Dockerfile (default), buildpacks or a prebuilt image | Runtime auto-detection or Dockerfile |
| Free tier | None for new organisations since October 2024 | Yes — Nano + Starter Postgres + cron + preview |
| Managed databases | Managed Postgres; Redis via Upstash | Postgres, MySQL, MariaDB, MongoDB, Redis |
| Postgres version upgrades | Not yet included (per Fly’s docs) | In place, one command (databases up to 1 GB) |
| Regions | 17; in Europe ams, arn, cdg, fra, lhr | Helsinki, FI (EU only) |
| Scale to zero | auto_stop_machines (rootfs and volumes still billed) | Free Nano sleeps after 60 min idle; paid services stay on |
| Company | Fly.io, Inc. (US, California law) | MICCI (Denmark) |
| DPA | Pre-signed DPA available | At signup, every plan |
| Billing | USD, card required | EUR, EU VAT invoices |
Migration gotchas
release_command and the pre-deploy command run at different moments.
Fly runs release_command once per deploy, in a temporary machine built from the new image with no volumes attached, and stops the deploy if it fails. HostStack runs the pre-deploy command inside the new container after it passes its health check and before it takes traffic — so the new version starts once against the old schema. If it fails or runs past 10 minutes, the deploy fails and the previous version keeps serving.
Fly secrets cannot be exported.
Fly never shows a secret’s plain-text value back, by design. Budget time to gather the values from your password manager or the original source before cutover, and rotate anything you cannot find.
One region, not seventeen.
If you spread machines across regions for latency, that does not come with you: a HostStack project runs in Helsinki. For an app whose users are in Europe that is usually fine; for one serving every continent, it is the reason to stay.
auto_stop_machines has no paid equivalent.
Paid HostStack services are always on and billed flat per size; only a free-tier Nano sleeps, after 60 minutes without traffic, and wakes on the next request.
The root filesystem is read-only.
A Dockerfile that worked on Fly can still fail here if the app writes next to its code at runtime. Write to /tmp or a volume instead — see Container runtime in the docs.
Migration steps
- 1Sign up at hoststack.dev — no card for the free tier — and connect GitHub, GitLab, Bitbucket or Codeberg.
- 2Create a web service from the repo you deploy to Fly, without picking a runtime or commands, and HostStack builds the Dockerfile at its root. For a Dockerfile elsewhere, or a service that already exists, run hoststack services update svc_... --dockerfile-path <path>; without a Dockerfile, HostStack detects the runtime and builds it. Put fly.toml’s internal_port in hoststack.yaml as port — it becomes PORT in the container.
- 3Recreate your secrets. fly secrets list shows names and digests, never values, so collect the values from where you keep them into a .env file and run hoststack env import svc_... .env. It is a dry run that lists what would change; add --apply to write. Non-secret [env] values go in hoststack.yaml.
- 4Turn release_command into a pre-deploy command: hoststack services update svc_... --pre-deploy-command "npm run migrate".
- 5Create a managed Postgres with hoststack db create and link it with hoststack db link, which injects DATABASE_URL. Dump the Fly database through a local tunnel — fly mpg proxy for Managed Postgres (it listens on localhost:16380), fly proxy 5432 -a <postgres-app> for the older unmanaged Fly Postgres — and restore the dump into the new database with external access turned on.
- 6If the app keeps files on a Fly volume, pack them into a .tar.gz and upload it on the HostStack volume’s Storage tab.
- 7Point DNS at HostStack once the deploy is live and the certificate is issued. Keep the Fly app running until traffic has moved, then destroy it.
Frequently asked questions
Does HostStack read fly.toml?
No. The parts of fly.toml that describe your app move into a hoststack.yaml: internal_port becomes port, [env] becomes env and a [[mounts]] entry becomes disk. The build is your Dockerfile (picked up from the repo root when the service is created, or set with --dockerfile-path) or HostStack’s runtime detection, and release_command becomes the service’s pre-deploy command. Regions, machine counts and auto-stop settings have no equivalent — HostStack runs the service in Helsinki at the size you pick.
How do I get my data out of Fly Managed Postgres?
Fly Managed Postgres is not reachable from the public internet, so open a tunnel with fly mpg proxy, which listens on localhost:16380, and run pg_dump against the connection string with flympg.net replaced by localhost. Restore that dump into a HostStack Postgres with external access turned on, then link the database to your service so DATABASE_URL is injected.
Can I keep the Dockerfile I deploy to Fly?
Yes. A service created from the repo without a runtime or commands builds the root Dockerfile on its own; otherwise point the service at it with hoststack services update svc_... --dockerfile-path Dockerfile, and HostStack builds exactly that file. It runs with a read-only root filesystem and a reduced set of capabilities, and must listen on 0.0.0.0 at the port in PORT.
Is there a free tier like Fly’s old Hobby plan?
Yes. Fly deprecated its plans in October 2024, and new organisations get a trial instead of a free allowance. HostStack’s free tier is one Nano service, one Starter Postgres, one cron job and one preview environment, with no card and no end date. The Nano sleeps after 60 minutes without traffic; the database does not.