podfly 0.8.0
podfly: ^0.8.0 copied to clipboard
Deploy Serverpod apps on Fly, Railway, DigitalOcean, Render, Cloud Run, AWS, Azure, and Hetzner via existing cloud CLIs. Thin orchestrator (not a host): podfly.yaml, Docker quirks, Flutter web packagi [...]
Changelog #
All notable changes to podfly are documented in this file.
The format is based on Keep a Changelog, and this project aims to follow Semantic Versioning.
[Unreleased] #
Planned (parked) #
- Upstash Redis (optional): wire Serverpod Redis host/password/SSL for multi-instance cache/PubSub — not required for small/stateless apps
0.8.0 — 2026-07-22 #
Added #
web_host: vercel— Flutter web static on Vercel (same role as Cloudflare Pages)- Creates project if missing (
vercel project add), thenvercel deploy … --prod - Writes
vercel.json(SPA rewrites + WASM / cache headers) unless project provides one - Doctor:
vercelCLI +vercel whoami/VERCEL_TOKEN - Example: vercel/split_fly, vercel/realtime_split
- Creates project if missing (
web_host: netlify— Flutter web static on Netlify- Creates site if missing (
--site-name), thennetlify deploy --dir … --prod --no-build - Writes
netlify.toml(SPA rewrites + WASM / cache headers) unless project provides one - Doctor:
netlifyCLI +netlify status/NETLIFY_AUTH_TOKEN - doc/netlify.md — config, CI token, realtime split, teardown
- Examples: netlify/split_fly, netlify/realtime_split
- Creates site if missing (
web_host: github_pages— Flutter web static on GitHub Pages- Creates repo if missing (
gh repo create), force-pushesgh-pagesbranch - Writes
.nojekyll+404.htmlSPA fallback; autobase_href: /<repo>/ - Doctor:
gh+git+gh auth status - doc/github_pages.md
- Examples: github_pages/split_fly, github_pages/realtime_split
- Creates repo if missing (
- Top-level
web_host:cloudflare(default) |vercel|netlify|github_pages - Refactor:
StaticWebDeployerfor Pages/Vercel/Netlify/GitHub Pages - Docs:
llms.txt,AGENTS.md, guide/ci/podfly.yaml updated for static CDN matrix + realtime split
0.7.0 — 2026-07-21 #
Added #
host: hetzner(aliaseshcloud,hetzner_cloud): Hetzner Cloud VPS- Interactive: pick existing server or create (location → type from live API)
- Non-interactive: bound
server_id/ipv4orcreate: true+ policy - Local Docker build →
docker save \| ssh docker load→ container on :8080 - Caddy HTTPS :443 (Let's Encrypt) via PTR hostname or
hetzner.domain - Ubuntu pin + remote Docker bootstrap; WebSockets OK
- Examples: hetzner/api_only, hetzner/realtime_monolith
- doc/hetzner.md — bind vs create, domains/HTTPS, teardown
DeployContext.nonInteractivefrompodfly deploy --yes
0.6.0 — 2026-07-21 #
Added #
host: azure(aliasesaca,containerapps,container_apps): Azure Container Apps- Local Docker build (
linux/amd64) → ACR (Basic, admin) → managed environment + app - Creates resource group / ACR / environment when missing; external ingress, target port 8080
- Scale-to-zero via
min_replicas: 0; WebSockets supported (unlike App Runner) - Config: app, resource_group, location, environment, registry, cpu/memory, replicas
- Local Docker build (
- Examples: azure/api_only, azure/realtime_monolith
- doc/azure.md — deploy flow, teardown (delete resource group)
host: aws_ecs(aliasesecs,fargate): ECS Fargate + ALB (WebSocket-capable)- Docker → private ECR → task definition → Fargate service behind internet-facing ALB
- ALB idle timeout (default 3600s), optional stickiness; HTTP :80 for demos (no ACM)
- Example: aws/ecs_realtime
- AWS App Runner
ecr_public: true— push to ECR Public +ImageRepositoryType: ECR_PUBLIC - Prefer monorepo root Dockerfile when present (nginx monolith images)
- Example: aws/realtime_monolith
- doc/aws.md — App Runner WebSocket limitation (managed Envoy 403)
- Sketch: ECS Fargate + ALB realtime
Changed #
- Cloud Run: always pass
--execution-environment(defaultgen2viacloud_run.execution_environment)
0.5.0 — 2026-07-21 #
Added #
host: aws(aliasesapprunner,app_runner,amazon): AWS App Runner deploy- Local Docker build (
linux/amd64) → ECR push →create-service/update-service - Auto-creates ECR repository +
AppRunnerECRAccessRole(ECR pull) when missing - Config: region, cpu/memory, port, ecr_repository,
start_command, service_arn, env - Default
start_command: /app/entrypoint.sh(App Runner often fails CREATE without it) - TCP health check (works without a custom HTTP path)
- Local Docker build (
- Example: podfly_examples/aws/api_only
0.4.1 — 2026-07-21 #
Added #
- Cloud Run
timeout_seconds(default 300, max 3600) andsession_affinityfor long-lived WebSockets - Example: podfly_examples/gcp/realtime_monolith — Flutter web + Serverpod streams in one Cloud Run service (nginx monolith)
0.4.0 — 2026-07-21 #
Added #
host: cloud_run(aliasesgcp,google,cloudrun): Google Cloud Run API deploy viagcloud run deploy --source- Config: project, region, memory/cpu, min/max instances, Cloud SQL instance attach list
- Copies server Dockerfile to monorepo root when needed (Cloud Run source build)
- Auth: active
gcloudaccount orGOOGLE_APPLICATION_CREDENTIALS - Positioning: inexpensive stateless Serverpod (not GCE/Terraform)
- Example: podfly_examples/gcp/api_only
0.3.1 — 2026-07-20 #
Added #
- Render static sites for Flutter web (
deployWeb): stagesite/, git push,static_siteservice - Example: podfly_examples/render/api_and_static
Fixed #
- Resolve Render service URL by service id (avoid picking another
*.onrender.com) - Smoke
web:usesrender.web_public_hostwhen set
0.3.0 — 2026-07-20 #
Added #
host: render: Render web service (git + Docker) viarenderCLI- Monorepo support via
render.root_dir(maps to RenderrootDir) - Generates starter
render.yamlBlueprint when missing - Auth:
render loginorRENDER_API_KEY
- Monorepo support via
database.provider: render_postgres: create/lookup free/paid PG, fetch connection info, sidecar + Serverpod config patch- Examples monorepo: podfly_examples (
fly/api_only,render/api_postgres)
Changed #
- Provider roadmap: Render marked supported (was planned)
0.2.2 — 2026-07-20 #
Added #
- README hero image (
doc/images/podfly-hero.jpg)
Changed #
- Docs: clarify value prop —
serverpod createthenpodfly deployis enough;fly.toml/ host configs are generated when missing (examples commit them only for stable CI) - Docs: Serverpod version compatibility — 4.x primary; Serverpod 3.4.11 smoke-tested on Fly (mini +
none, server template +fly_postgres) - Example
mobile_api_onlyREADME: product story, optionalfly.toml, greenfield setup path
0.2.1 — 2026-07-20 #
Added #
- Example CI:
example/mobile_api_onlyGitHub Actions workflows for Fly API-only deploy on every push tomain(+ PR dry-run) - Live demo repo: 127thousand/podfly-api-only-demo
Fixed #
- Doctor no longer hard-requires Flutter for API-only deploys (
--apiorweb.enabled: false) — unblocks GitHub Actions without Flutter SDK
0.2.0 — 2026-07-20 #
Added #
host: digitalocean(aliasdo): App Platform viadoctl+ DOCR- Local Docker build/push (
linux/amd64), app spec create/upsert - API app + optional separate web app (nginx + Flutter build)
digitalocean_postgres: Managed Postgres (DBaaS), public SSL host, app firewallapp:<id>- Starter DOCR: one repository with tags
api/web
- Local Docker build/push (
mode: monolithas the canonical name for “UI with API host / no Pages” (replacesmode: flyas primary)
Changed #
mode: flyremains a legacy alias formonolith- Native web hosts (Railway / DigitalOcean): deploy API before web so Flutter bakes a live
SERVER_URL - nginx static template: set WASM
Content-Typeviadefault_type(notadd_header) so CanvasKit loads (avoids blank Flutter canvas)
Fixed #
- Duplicate
Content-Type: application/wasm,application/wasmbroke Flutter web on DO/Railway nginx deploys
0.1.1 — 2026-07-20 #
0.1.0 — 2026-07-20 #
First public release on pub.dev.
Features #
Host adapter architecture
- Host adapter registry (
lib/src/hosts/): Fly, Railway, and planned clouds asHostAdapterplugins - Wizard chooses API cloud (
host:inpodfly.yaml); doctor only requires that host’s CLI - Planned hosts (Render, Cloud Run, AWS, Azure): config + doctor install recipes; deploy not implemented yet
Fly.io
- Default API host with scale-to-zero-friendly
fly.tomltemplates fly apps createwhen missing (+ unique suffix if name taken); app name sanitize- Patch Serverpod
production.yamlpublicHostto*.fly.dev HostAdapter.ensureApiApp: create API app before database attachfly_postgres: create cluster, attach, parseDATABASE_URL→ sidecar + Serverpod user/db/passwords.yaml
Railway
- First-class API host (
host: railway): project/service, domain,railway.toml,railway up - Full stack: separate API + static web (nginx) + optional Postgres
railway_postgresprovider with sidecar →production.yaml/passwords.yaml- Serverless by default for API + web
- Optional CDN on web service
Cloudflare Pages
- Split mode: Flutter web → Pages via
wrangler
Doctor, database, CLI
- Doctor can install missing CLIs; facilitated login on TTY;
PODFLY_AUTO=1 - Providers:
none,sqlite,fly_postgres,neon,railway_postgres - Detect mobile / API-only monorepos; Flutter web packaging (CanvasKit, bootstrap)
- Commands:
deploy,doctor,init,smoke; CI-friendly--yes --no-login
Documentation #
- README, user guide, CI, caching, database, config reference, AGENTS.md, llms.txt
Links #
- Package: pub.dev/packages/podfly
- Repo: github.com/127thousand/podfly
- Docs: doc/README.md