Deploy a Django App on Heroku

Blog / Django · June 11, 2019 · Updated June 10, 2026 · 8 min read
Deploy a Django App on Heroku

To deploy a Django app on Heroku in 2026, add a Procfile containing web: gunicorn project.wsgi, pin your Python version, list gunicorn, dj-database-url, whitenoise and psycopg[binary] in requirements.txt, then run heroku create, git push heroku main and heroku run python manage.py migrate. The one thing that changed since older tutorials: Heroku removed its free tier in November 2022, so you now deploy onto a paid Eco or Basic dyno — there is no free option anymore.

Heroku is still one of the fastest ways to ship a Django project: you push to git and the platform builds your app, installs dependencies, collects static files and starts your web process. This guide covers the modern workflow end to end, the production settings that trip people up (ALLOWED_HOSTS, DEBUG, static files), and honest alternatives if you specifically need a free tier.

Key takeaways

  • Heroku has no free tier since November 2022 — the cheapest options are the paid Eco and Basic dynos (check heroku.com for current plans).
  • A working Django deploy needs four files: requirements.txt, a Procfile, a Python version file (.python-version), and production-ready settings.py.
  • Use dj-database-url to read Heroku's DATABASE_URL and WhiteNoise to serve static files without S3.
  • Deploy with git push heroku main (not master) and apply migrations with heroku run python manage.py migrate.
  • Set DEBUG=False and a correct ALLOWED_HOSTS via config vars before going live.
  • If you need a genuinely free option, look at Render, Railway or Fly.io — compared below.

Is Heroku still free in 2026?

No. Heroku shut down all of its free product plans on 28 November 2022, including free dynos, free Postgres and free Redis. Many older Django-on-Heroku tutorials still tell you to deploy for free — that advice is out of date.

Today the entry-level dynos are Eco and Basic (both paid), and managed Postgres starts at the Essential tiers. We don't quote dollar figures here because Heroku adjusts plan pricing periodically — always confirm the current numbers on heroku.com. The Eco dyno plan lets a dyno sleep after inactivity, which keeps a hobby setup inexpensive.

If a free tier is a hard requirement, see the alternatives in the next section — Render, Railway and Fly.io all still offer some free or trial usage.

Heroku vs Render vs Railway vs Fly.io vs AWS Elastic Beanstalk

Many readers arrive looking for the old free Heroku. Here is an honest comparison of the platforms Django developers most often choose in 2026.

Platform Free tier? Managed Postgres Ease of setup Scaling Best for
Heroku No (ended Nov 2022) Yes (add-on) Very easy Manual or auto dynos Teams wanting a proven git-push PaaS
Render Limited free web service (spins down) Yes (free 90 days, then paid) Very easy Auto-scaling A Heroku-style workflow on a budget
Railway Trial credit, no permanent free Yes (built-in) Very easy Usage-based Fast prototypes and side projects
Fly.io Pay-as-you-go with a small allowance Yes (Fly Postgres) Moderate Global edge VMs Low-latency, multi-region apps
AWS Elastic Beanstalk No (you pay for EC2 and RDS) Via Amazon RDS Moderate to complex Full AWS auto-scaling Teams already on AWS needing control

For an AWS-native path, we have a dedicated walkthrough on deploying Django on Elastic Beanstalk. If you would rather self-host on a VM, see hosting Django with Nginx and uWSGI.

What do you need before you deploy?

  • A working Django project in a git repository.
  • The Heroku CLI installed, plus a Heroku account.
  • Python and pip locally, ideally inside a virtual environment.
  • A PostgreSQL mindset: Heroku runs Postgres in production, so avoid SQLite-only assumptions in your settings.

Install the Heroku CLI from the official site, then authenticate:

heroku login

How do you prepare your Django project for Heroku?

You need four things in your project root. Start with requirements.txt — Heroku's Python buildpack reads it to install your dependencies:

Django>=5.0
gunicorn
dj-database-url
whitenoise[brotli]
psycopg[binary]

gunicorn is the production WSGI server, dj-database-url parses Heroku's DATABASE_URL, whitenoise serves static files straight from the dyno, and psycopg[binary] is the modern PostgreSQL driver (the successor to psycopg2).

Next, the Procfile (no file extension) tells Heroku what process to run. Replace project with your Django project package — the folder that holds wsgi.py:

web: gunicorn project.wsgi --log-file -
release: python manage.py migrate

The optional release: line runs database migrations automatically on every deploy, before the new dynos start — a clean, modern alternative to migrating by hand.

Then pin your Python version. Heroku now recommends a .python-version file containing just the major.minor version:

3.12

(The older runtime.txt with a value like python-3.12.8 still works but is being phased out in favour of .python-version.)

Finally, make settings.py production-ready: read the database from DATABASE_URL, wire up WhiteNoise, and drive DEBUG and ALLOWED_HOSTS from environment variables.

import os
import dj_database_url

DEBUG = os.environ.get('DEBUG', 'False') == 'True'

# Heroku serves apps from <app>.herokuapp.com (plus any custom domain)
ALLOWED_HOSTS = ['.herokuapp.com']
custom_host = os.environ.get('APP_HOST')
if custom_host:
    ALLOWED_HOSTS.append(custom_host)

# Parse Heroku's DATABASE_URL into Django's DATABASES setting
DATABASES = {
    'default': dj_database_url.config(
        default=os.environ.get('DATABASE_URL'),
        conn_max_age=600,
        ssl_require=True,
    )
}

# WhiteNoise must sit directly after SecurityMiddleware
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ... your remaining middleware
]

STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# Django 5.x static-file storage (compresses + fingerprints assets)
STORAGES = {
    'default': {'BACKEND': 'django.core.files.storage.FileSystemStorage'},
    'staticfiles': {'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage'},
}

This replaces the old DjangoWhiteNoise(application) wrapper that many 2016-era tutorials show — that API was removed years ago. The middleware-plus-STORAGES approach above is the current, supported way to serve static files.

Heroku runs python manage.py collectstatic automatically during the build, so you rarely call it yourself. To skip it, set heroku config:set DISABLE_COLLECTSTATIC=1.

How do you deploy the app to Heroku?

With the four files committed to git, create the app, provision Postgres, set your config vars, and push:

# create the app (Heroku generates a name if you omit one)
heroku create my-django-app

# provision managed Postgres (paid Essential tier)
heroku addons:create heroku-postgresql:essential-0

# production config vars
heroku config:set DEBUG=False
heroku config:set DJANGO_SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(50))')"

# deploy by pushing your main branch
git push heroku main

# run pending migrations and create an admin user
heroku run python manage.py migrate
heroku run python manage.py createsuperuser

# open the live app in your browser
heroku open

Note the branch name: modern git repos use main, so push with git push heroku main. Older guides say git push heroku master — only use master if that is genuinely your default branch.

heroku config:set stores secrets (database URLs, API keys, your SECRET_KEY) as environment variables — never commit these to git. Configuring transactional email, for instance, is just another config var; see our guide on sending emails with SendGrid on Heroku.

Can you deploy Django to Heroku with Docker?

Yes. If you already containerise your app, use Heroku's Container Registry instead of the git buildpack flow:

# switch the app to the container stack
heroku stack:set container

# build and push your image, then release it
heroku container:push web
heroku container:release web

You can also commit a heroku.yml manifest to build from your Dockerfile on every git push. If you are new to containerising Django, start with our walkthrough on deploying a Django project in a Docker container.

Common Heroku deployment errors (and fixes)

  • Static files or CSS not loading — confirm WhiteNoise is in MIDDLEWARE, STATIC_ROOT is set, and collectstatic ran during the build. The CompressedManifestStaticFilesStorage backend handles hashing and compression.
  • DisallowedHost / Bad Request (400) — add .herokuapp.com (and any custom domain) to ALLOWED_HOSTS.
  • App boots but shows debug pages — you left DEBUG=True. Always run production with DEBUG=False.
  • relation does not exist — you skipped migrations; run heroku run python manage.py migrate (or add the release: phase).
  • H14 - no web processes running — your Procfile web line is missing or misspelled; it must read web: gunicorn project.wsgi.
  • Application crashed on boot — check heroku logs --tail for the real traceback.

Need help shipping Django to production?

Heroku is a great starting point, but production Django often grows into Postgres tuning, background workers, CI/CD and cost control. Our team has delivered 50+ projects and can help you ship faster — explore our Django development services, or, if you are weighing a move to AWS or another platform, our cloud migration services cover the full path. We use AI-assisted workflows to ship features and fixes in days, not months.

Frequently Asked Questions

Is Heroku free for Django apps in 2026?

No. Heroku ended all free product plans on 28 November 2022. To run a Django app you now need at least a paid Eco or Basic dyno plus a paid Postgres plan. Check heroku.com for current pricing, or use Render, Railway or Fly.io if you specifically need free or trial usage.

What is a Procfile and what should it contain for Django?

A Procfile is a plain-text file in your project root that declares the commands Heroku runs. For Django the minimum is a web process started by gunicorn: web: gunicorn project.wsgi, where project is the package containing wsgi.py. You can add a release: python manage.py migrate line to migrate automatically on each deploy.

How do I run Django migrations on Heroku?

Run heroku run python manage.py migrate from your terminal to apply migrations on a one-off dyno. For automation, add a release: python manage.py migrate line to your Procfile so migrations run on every deploy, before the new dynos start serving traffic.

Why are my static files not loading on Heroku?

Heroku does not serve Django static files by default. Install WhiteNoise, add whitenoise.middleware.WhiteNoiseMiddleware directly after SecurityMiddleware, set STATIC_ROOT, and use the CompressedManifestStaticFilesStorage backend. Heroku runs collectstatic during the build automatically, so your CSS and JS are then served from the dyno.

Should I push to Heroku with main or master?

Push whichever branch is actually your default. Modern git and GitHub use main, so git push heroku main is correct for most new projects. Older tutorials use git push heroku master; only use master if that is still your repository's default branch.

What are the best alternatives to Heroku for Django?

Render and Railway offer the closest Heroku-style git-push experience with managed Postgres and some free or trial usage. Fly.io is strong for low-latency, multi-region apps, while AWS Elastic Beanstalk gives the most control if you are already on AWS. Each differs in free tier, ease and scaling — see the comparison table above.

Share this article