Porting an app from Heroku, Scalingo, or elsewhere¶
Already running somewhere else — Heroku, Scalingo, Render, or just a bare Flask/Rails
app? Moving to Allocus is mostly a mechanical translation of your platform's config
into a Dockerfile + allocus.yaml. The easiest way is to open the repo in Claude
and say "deploy this to allocus" — the skill recognizes these setups and does the
translation. Here's what it's doing, so you can do or check it yourself.
The translation table¶
| What you have | What it becomes on Allocus |
|---|---|
Procfile web: <cmd> |
Your container's start command → CMD in the Dockerfile. |
worker: / clock: process types |
Extra services in a stack (own build:, no public port). |
runtime.txt, .python-version, .nvmrc |
The version to pin your Dockerfile base image to. |
A Postgres / Redis addon (DATABASE_URL, REDIS_URL) |
A db / redis service in a stack; point the env var at it by name. |
app.json / scalingo.json env vars |
Entries under the service's environment:. |
Aptfile or apt buildpack |
apt-get install … in the Dockerfile. |
| A static site with a build step | Build in one stage, serve with an nginx image. |
App binds $PORT (a PaaS convention) |
Pick a fixed port, set it in allocus.yaml, and bind it. |
The end state is always a real Dockerfile committed to your repo — the whole
point is that the app no longer depends on the other platform's buildpacks.
Worked example: a Heroku Flask app¶
Say the repo has this, and no Dockerfile:
Procfile → web: gunicorn app:app
runtime.txt → python-3.12
requirements.txt
app.py → a Flask app, plus a Heroku Postgres addon (DATABASE_URL)
Because there's a database, this becomes a small stack.
Dockerfile (from runtime.txt + the Procfile web command):
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt gunicorn
COPY . .
EXPOSE 8080
CMD ["gunicorn", "-b", "0.0.0.0:8080", "app:app"] # (1)
- Heroku set the port via
$PORT; on Allocus you pick it (8080) and bind it explicitly.
allocus.yaml (the app + its database, replacing the Heroku Postgres addon):
name: my-flask-app
services:
web:
build: .
port: 8080
expose: true
environment:
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app # was the Heroku addon
db:
image: postgres:16
volumes: ["pgdata:/var/lib/postgresql/data"]
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: app
Then set the password once — it goes in the encrypted secret store, not in git — and deploy:
Your app is live at https://my-flask-app.<you>.allocus.dev, with its own Postgres
running alongside it on your box.
Bring your data
This stands up an empty database. Migrating existing data (a pg_dump restore,
for instance) is a one-time step outside the deploy — ask Claude for the exact
commands for your setup.
What you give up by leaving¶
Worth knowing before you move something you depend on, because these are real differences rather than a rough edge that'll be smoothed later:
| On Heroku/Render | On Allocus |
|---|---|
| Managed Postgres with automatic backups and PITR | Postgres is a container on your box. Nothing backs it up — that's your job. |
| Dynos scale horizontally | One box, one machine's worth of capacity. You can size it up, not out. |
| An uptime SLA | None. One operator, best effort. |
| A per-app bill that grows | One flat price, however many apps you deploy. |
The last row is the trade you're making, and the first row is what it costs. For side projects, internal tools and things you'd redeploy from git anyway, that's a good deal. For something with a real durability requirement, keep the database managed and put only the app on Allocus.
If it's a single process with no database¶
Even simpler — no stack needed. A Dockerfile derived from your Procfile/runtime,
plus a two-line allocus.yaml:
See the Quickstart for the single-container path.