Why this migration is easy
If you're on Render, you already think in terms of long-running web services, background workers, managed Postgres, and cron jobs. PandaStack uses the same primitives, so this is one of the cleaner migrations you can do — there's no serverless-to-container paradigm shift to absorb.
The motivations to switch are usually flat-rate pricing predictability, built-in auto-wired databases, edge functions included on every tier, and the architecture (rootless BuildKit, gVisor sandboxing on free tier, KEDA scale-to-zero). Render is a solid platform; check its [pricing](https://render.com/pricing) and decide on the merits.
Concept mapping
| Render | PandaStack |
|---|---|
| Web Service | Container app |
| Static Site | Static site |
| Background Worker | Container app (long-running) |
| Cron Job | Cronjob |
| Managed PostgreSQL | Managed PostgreSQL (14.x / 16.x) |
| Render Key Value (Redis) | Managed Redis |
render.yaml | Auto-detected build/start + dashboard config |
| Environment Groups | Env vars (per app) |
Step 1: Read your render.yaml
Your render.yaml is the source of truth for what you're running. Extract the build command, start command, env vars, and which services talk to which database.
# render.yaml (what you're migrating from)
services:
- type: web
name: api
env: node
buildCommand: npm ci && npm run build
startCommand: npm start
envVars:
- key: DATABASE_URL
fromDatabase: { name: app-db, property: connectionString }Note the buildCommand and startCommand — you'll reuse them. Note the database link — PandaStack does the same auto-wiring.
Step 2: Bind to the injected port
Render injects PORT and so does PandaStack. If your app already reads process.env.PORT (which Render required), you're done — no change needed.
const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => console.log(`up on ${port}`));Binding to 0.0.0.0 (not 127.0.0.1) matters inside containers.
Step 3: Migrate the database
Provision a managed PostgreSQL on PandaStack matching your Render version (14.x or 16.x). Then a standard dump/restore:
# Render exposes an external connection string in its dashboard
pg_dump --no-owner --no-acl "$RENDER_DATABASE_URL" -Fc -f app.dump
pg_restore --no-owner --no-acl -d "$PANDASTACK_DATABASE_URL" app.dumpFor minimal downtime, do this during a brief maintenance window, or use logical replication if you need near-zero downtime (covered in our database migration guide). For most apps a short window is fine.
Once the DB is attached to your app, DATABASE_URL is injected automatically — you can drop the manual env var.
Step 4: Connect your repo and push
Connect the same Git repository in the PandaStack dashboard. It auto-detects Node/Python/Go/etc., infers build and start, and builds on push:
git push origin mainThe build runs in an ephemeral Kubernetes Job pod with rootless BuildKit, the image lands in Google Artifact Registry, and Helm deploys it. You get live build and app logs streamed from self-hosted Elasticsearch — comparable to Render's log view.
Step 5: Move cron jobs and workers
- Cron jobs: recreate each Render cron job as a PandaStack cronjob with the same schedule expression and command.
- Background workers: deploy as a normal container app with your worker start command. There's no special worker type to learn.
# A worker is just a container with a different start command
npm run workerStep 6: Env vars and environment groups
Render's Environment Groups become per-app env vars on PandaStack. Recreate them, keeping identical key names so no code changes. Attach managed services (DB, Redis) and let their connection strings auto-wire.
Step 7: Domains and cutover
Add your custom domain; SSL provisions automatically (Cloudflare DNS, Kong ingress). Validate the app on its PandaStack URL first, lower DNS TTL ahead of time, then repoint the record. Keep the Render service running until DNS fully propagates, then tear it down.
Honest trade-offs
- Maturity: Render has been around longer with a deep feature set and large community. PandaStack is newer; the ecosystem is still growing.
- Free-tier behavior: PandaStack free-tier apps scale to zero on spot nodes (gVisor sandbox), so expect cold starts after idle. Paid tiers stay warm.
- Free-tier DB storage: sized for dev/hobby, not production datasets.
What you gain: edge functions on every tier, server-side metrics and analytics without a client SDK (ClickHouse), and predictable flat plans — Free $0, Pro $15/mo, Premium $25/mo.
References
- [Render pricing](https://render.com/pricing)
- [Render — render.yaml reference](https://render.com/docs/blueprint-spec)
- [PostgreSQL pg_restore documentation](https://www.postgresql.org/docs/current/app-pgrestore.html)
- [KEDA — Kubernetes event-driven autoscaling](https://keda.sh/docs/latest/concepts/)
---
Because both platforms are container-first, this migration is mostly copy-paste of build/start commands plus a database dump. Stand up your services on PandaStack's [free tier](https://dashboard.pandastack.io) alongside Render, validate, then cut over DNS when you're confident.