How to Migrate from Heroku: Step-by-Step Guide
Heroku's free tier removal changed everything. Thousands of developers suddenly needed a new home for their apps — one that still offered the simple, git-driven workflow they loved, without the runaway pricing of Heroku's paid tiers. This guide walks you through every step of migrating off Heroku, from exporting your database to redeploying your first container.
What You're Actually Migrating
Before you touch a single config file, inventory what you have:
- Web dynos — your main application process
- Worker dynos — background job processors
- Scheduler tasks — recurring cron-style jobs
- Heroku Postgres — your relational database
- Config vars — environment variables
- Buildpacks — your runtime environment
Each of these maps directly to something on a modern PaaS like PandaStack.
Step 1: Export Your PostgreSQL Database from Heroku
Start with data — it's the most critical thing to get right.
# Capture a Heroku Postgres backup
heroku pg:backups:capture --app your-app-name
# Download the latest backup
heroku pg:backups:download --app your-app-name
# This creates latest.dump in your current directory
ls -lh latest.dumpHeroku exports in pg_dump custom format. Keep this file safe — you'll restore it into your new database.
Step 2: Export Your Config Vars
# List all config vars
heroku config --app your-app-name
# Export as shell-compatible format
heroku config --shell --app your-app-name > heroku-env.txt
# Review before using
cat heroku-env.txtNever commit this file. It contains secrets. Use it only as a reference when configuring your new environment.
Step 3: Containerize Your Application
Heroku used buildpacks to detect your runtime. On PandaStack, you deploy Docker containers. If you don't have a Dockerfile yet, create one now.
For a Node.js app:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"]For a Python app:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]Test your container locally before deploying:
docker build -t my-app .
docker run -p 3000:3000 --env-file heroku-env.txt my-app
curl http://localhost:3000/healthStep 4: Provision a New PostgreSQL Database on PandaStack
Log into [dashboard.pandastack.io](https://dashboard.pandastack.io), navigate to Databases, and create a new PostgreSQL instance. PandaStack supports PostgreSQL, MySQL, Redis, and MongoDB on its free and paid tiers (paid plans from $12/mo).
Once provisioned, copy the connection string from the dashboard, then restore your Heroku backup:
# Restore the Heroku pg_dump backup into your new PandaStack database
pg_restore --no-acl --no-owner --verbose -d "postgresql://user:password@host:5432/dbname" latest.dump
# Verify row counts match
psql "postgresql://user:password@host:5432/dbname" -c "SELECT schemaname, tablename, n_live_tup FROM pg_stat_user_tables ORDER BY n_live_tup DESC;"Step 5: Deploy Your Container to PandaStack
Install the CLI and connect your GitHub repository:
npm install -g @pandastack/cli
panda login
panda init
# Link your GitHub repo (PandaStack deploys on every push)
panda deploy --image ghcr.io/your-org/your-app:latestPandaStack integrates with GitHub only — every push to your configured branch triggers an automatic deploy. Set your environment variables in the dashboard under Settings → Environment Variables, copying them from your heroku-env.txt reference.
Step 6: Migrate Heroku Scheduler Tasks to Cronjobs
Any Heroku Scheduler tasks become PandaStack cronjobs:
# Create a cronjob for a task that ran every hour on Heroku
panda cronjob create --name cleanup-sessions --image ghcr.io/your-org/your-app:latest --schedule "0 * * * *" --command "node scripts/cleanup.js"Step 7: DNS Cutover
Once your new deployment is verified and healthy, update your DNS records to point to PandaStack. Do this during a low-traffic window and keep your Heroku app running for at least 24 hours as a fallback until TTLs expire.
Checklist Before You Flip DNS
- [ ] Database restored and row counts verified
- [ ] App boots successfully in container
- [ ] All environment variables set in new dashboard
- [ ] Health check endpoint returns 200
- [ ] Cronjobs created and tested
- [ ] SSL certificate provisioned
- [ ] Monitoring configured
Migrating from Heroku is a weekend project, not a quarter-long initiative. With a Dockerfile and your database backup in hand, you can be fully migrated in a few hours. Visit [docs.pandastack.io](https://docs.pandastack.io) for platform-specific configuration guides.