Migrating from Heroku
Vessl and Heroku share a lot of concepts (Git-based deploys, environment variables, add-ons, background workers), but the underlying model is different: Vessl runs your app on a server you own, while Heroku runs it on shared infrastructure you rent per dyno.
This guide walks through the main differences and what to do for each.
Concept mapping
| Heroku | Vessl equivalent |
|---|---|
| Dyno | App replica (container) |
Procfile web: | Start command in app Settings |
Procfile worker: | Daemon in the Daemons tab |
| Config vars | Variables tab |
| Heroku Postgres | PostgreSQL add-on |
| Heroku Redis | Redis add-on |
| Heroku Scheduler | Server cron job or daemon with a cron loop |
| Review apps | Not available — use staging projects |
| Pipelines | Not available |
heroku run | Console tab → Run Command |
heroku logs --tail | Logs tab |
heroku releases | Deployments tab |
heroku rollback | Deployments tab → Rollback |
Step 1 — Add a server
Vessl is BYOS (bring your own server). You need a VPS running Ubuntu — any provider works (DigitalOcean, Hetzner, Vultr, Contabo, etc.).
A server comparable to a Heroku Standard-1X dyno (512MB RAM) would be a 1GB RAM VPS. Most providers charge $4–6/month for this tier, and you can run multiple apps on it.
Once you have a VPS, follow Add your server to provision it.
Step 2 — Connect your GitHub repository
Vessl deploys from GitHub. If your Heroku app deploys from a Git remote, push it to GitHub first (or use the GitHub integration you may already have).
Follow Connect GitHub to link your GitHub account.
Step 3 — Migrate environment variables
In your Heroku app, run:
heroku config -a your-app-name
This lists all config vars. Copy them and paste them into Vessl's Variables tab. Don't include DATABASE_URL or REDIS_URL — Vessl injects those from add-ons automatically.
Step 4 — Migrate the database
Export from Heroku:
heroku pg:backups:capture -a your-app-name
heroku pg:backups:download -a your-app-name
# Downloads latest.dump
Restore to Vessl:
- Add a PostgreSQL add-on to your Vessl app (Overview → Connected Services → Add).
- Deploy the app at least once so the add-on is provisioned.
- Set up an SSH tunnel to your Vessl server's database:
ssh -L 15432:127.0.0.1:5432 <ssh-user>@<server-ip> -N
- Restore the dump:
pg_restore --host 127.0.0.1 --port 15432 \--username <DB_USERNAME> --dbname <DB_DATABASE> \--no-owner --no-privileges latest.dump
Replace <DB_USERNAME> and <DB_DATABASE> with the values from your app's Variables tab.
Step 5 — Handle the Procfile
Heroku reads Procfile to determine how to run your app. Vessl doesn't use Procfile directly — you set these in the app settings instead.
web: process → set as the Start command in Settings → Runtime & Release.
For example, if your Procfile has:
web: gunicorn myapp.wsgi:application --bind 0.0.0.0:$PORT
Set the start command to:
gunicorn myapp.wsgi:application --bind 0.0.0.0:${PORT:-8000}
worker: process → add a Daemon in the Daemons tab with the same command.
release: process → this maps to the Post-deploy command in Settings → Runtime & Release. Common examples:
# Rails
bundle exec rails db:migrate
# Django
python manage.py migrate
# Laravel
php artisan migrate --force
Step 6 — Heroku Scheduler
If you use Heroku Scheduler for recurring tasks, migrate them to either:
- Server cron jobs (Servers → your server → Cron Jobs) — for host-level tasks
- Daemon with a cron loop — for tasks that need your app's environment:
/bin/sh -c "while true; do php artisan schedule:run; sleep 60; done"
Step 7 — Deploy
Create the app in Vessl, select the repository and branch, review the auto-detected settings, and click Deploy.
After the first deploy succeeds, check the Logs tab to confirm your app is running correctly.
Common differences to watch out for
Ephemeral filesystem Like Heroku, your app's container filesystem is ephemeral — files written to disk (outside of a persistent volume) are lost on redeploy. If your app writes user uploads or generated files to disk, add a persistent volume and mount it at the path your app writes to.
PORT binding
Heroku injects $PORT and your app must listen on it. Vessl does the same. If your app already handles $PORT correctly for Heroku, it'll work on Vessl without changes.
SSL Heroku provisions SSL automatically on custom domains via their ACM. Vessl does the same via Let's Encrypt. See Custom domains & SSL.
Buildpacks
Vessl uses Nixpacks instead of Heroku buildpacks, but the auto-detection logic is similar for common stacks (Node.js, Python, Ruby, Go, PHP). If you have a Dockerfile, Vessl will use that instead.
One-off commands (heroku run)
Use the Console tab in Vessl. You can run any command inside the running container — rails console, python manage.py shell, php artisan tinker, etc.