Back to Blog
Guide10 min read2026-07-06

How to Migrate from Render to PandaStack

Render and PandaStack share a container-first philosophy, which makes migration refreshingly mechanical. Here's how to move your web services and databases with minimal downtime.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

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

RenderPandaStack
Web ServiceContainer app
Static SiteStatic site
Background WorkerContainer app (long-running)
Cron JobCronjob
Managed PostgreSQLManaged PostgreSQL (14.x / 16.x)
Render Key Value (Redis)Managed Redis
render.yamlAuto-detected build/start + dashboard config
Environment GroupsEnv 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.dump

For 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 main

The 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 worker

Step 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.

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also