Deploy Django on Scalingo

Deploy Django on Scalingo, the European PaaS: prepare a Procfile with web and postdeploy commands, add the PostgreSQL addon, configure environment variables, static files, and workers, and scale containers while keeping data in EU regions.

Problem statement

You want a Heroku-style workflow (git push, buildpacks, addons) with hosting and data in the European Union, for latency or compliance reasons. Scalingo is a French PaaS built on that model. If you have deployed Django to Heroku, most of it carries over: a Procfile, environment-based settings, WhiteNoise for static files, and a PostgreSQL addon. Scalingo adds a postdeploy process type that is a natural place for migrations.

Django on Scalingogit pushbuildpack buildProcfileweb, postdeployPostgreSQL addonURL in env varContainersscale web, workerA Heroku-like flow with a postdeploy step for migrations and EU-hosted data.
  1. Add gunicorn, whitenoise, dj-database-url, and psycopg[binary] to requirements.txt, and pin Python with .python-version.
  2. Create a Procfile with web: gunicorn config.wsgi --bind 0.0.0.0:$PORT and postdeploy: python manage.py migrate --noinput.
  3. Add the PostgreSQL addon; it sets SCALINGO_POSTGRESQL_URL (and DATABASE_URL in many setups); point Django at it.
  4. Set SECRET_KEY, ALLOWED_HOSTS (including .osc-fr1.scalingo.io or your region's domain), and DJANGO_SETTINGS_MODULE.
  5. Push with git push scalingo main, then scale with scalingo --app shop scale web:2.

Step-by-step solution

1. Prepare the app

# Procfile
web: gunicorn config.wsgi --bind 0.0.0.0:$PORT --workers 2 --log-file -
worker: celery -A config worker -l info
postdeploy: python manage.py migrate --noinput

The Python buildpack detects requirements.txt (or Pipfile and Poetry files) and runs collectstatic automatically unless DISABLE_COLLECTSTATIC=1 is set, like Heroku's.

2. Configure settings

import os
import dj_database_url

SECRET_KEY = os.environ["SECRET_KEY"]
DEBUG = False
ALLOWED_HOSTS = os.environ["ALLOWED_HOSTS"].split(",")
DATABASES = {
    "default": dj_database_url.parse(
        os.environ.get("DATABASE_URL") or os.environ["SCALINGO_POSTGRESQL_URL"],
        conn_max_age=60, conn_health_checks=True,
    )
}
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
STATIC_ROOT = BASE_DIR / "staticfiles"

Add WhiteNoise for static files. Scalingo's router terminates TLS and forwards X-Forwarded-Proto.

process typesweb: gunicorn config.wsgi --bind 0.0.0.0:$PORTworker: celery -A config worker -l infopostdeploy: python manage.py migrate --noinput1231Set by Scalingo; bind to all interfaces.2Scaled separately; starts at zero containers.3Runs once per deploy, before traffic moves.postdeploy is the Scalingo equivalent of a release phasedjango-deployment.com
If postdeploy fails, the deploy is aborted and the previous version keeps running.

3. Create the app and addons

scalingo create shop --region osc-fr1
scalingo --app shop addons-add postgresql postgresql-starter-512
scalingo --app shop env-set SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(50))')" \
  ALLOWED_HOSTS="shop.osc-fr1.scalingo.io,shop.example.com" \
  DJANGO_SETTINGS_MODULE=config.settings.production
git remote add scalingo git@ssh.osc-fr1.scalingo.com:shop.git
git push scalingo main

Check plan names with scalingo addons-plans postgresql; they change over time. Add a Redis addon the same way for caching and Celery.

4. Scale and run workers

scalingo --app shop scale web:2:M worker:1:M
scalingo --app shop run python manage.py createsuperuser

The worker type does not run until you scale it above zero. One-off containers from scalingo run use the same image and environment.

5. Domain, logs, and backups

Add your domain with scalingo domains-add shop.example.com; Scalingo issues a Let's Encrypt certificate. View logs with scalingo logs -f. The PostgreSQL addon includes backups depending on the plan; verify the retention and point-in-time recovery options match your needs.

what changes when moving from HerokuHerokuScalingoRelease phaserelease: in Procfilepostdeploy:Postgres URLDATABASE_URLSCALINGO_POSTGRESQL_URLDynosdynoscontainersRegionsUS and EUFrance (EU)Most of a Heroku Django setup moves over unchangeddjango-deployment.com
Reading either database variable in settings keeps the app portable.

Explanation

Scalingo follows the twelve-factor model popularized by Heroku: the buildpack turns a Git push into an image, process types from the Procfile run in isolated containers, and addons provide managed services through environment variables. The postdeploy type runs once after the build and before new web containers take traffic, which gives migrations the right timing. Data residency in EU regions is the main reason teams choose it for Django apps handling European personal data.

Edge cases / notes

  • Filesystem. Containers have an ephemeral disk; store media in object storage such as Scaleway Object Storage or S3-compatible services.
  • Long migrations. postdeploy has a time limit; split large data migrations into management commands run separately.
  • Python version. Check the buildpack's supported versions and use .python-version or the method the current buildpack documents.

Next steps

FAQ

How do I run migrations on Scalingo?

Add a postdeploy process type in the Procfile with python manage.py migrate --noinput.

Which environment variable has the database URL?

The PostgreSQL addon sets SCALINGO_POSTGRESQL_URL. Read it, or DATABASE_URL if present, in settings.

Where is Scalingo hosted?

In data centers in France, within the European Union.

How do I run Celery?

Add a worker process type and scale it to at least one container.

Keep going