Deploying to Heroku0%

Deploying to Heroku

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Deploying Django with Gunicorn and Docker

Deploying a production Django backend requires moving away from the single-threaded runserver to a robust, multi-process WSGI server. Modern enterprise deployments package Django into containerized Docker images orchestrated behind Gunicorn (Green Unicorn) and Nginx, deployed across cloud platforms (Heroku, AWS ECS, Google Cloud Run, or DigitalOcean).


1. The Production Architecture Stack

Output
User (Browser) ──► HTTPS (Port 443) ──► Nginx Reverse Proxy
│
▼ (Reverse Proxy / UNIX Socket)
Gunicorn WSGI Master Process
├── Worker 1 (Python Process)
├── Worker 2 (Python Process)
└── Worker 3 (Python Process)
│
▼
PostgreSQL Database
  • Nginx: Handles SSL termination, serves static/media files, and load balances requests.
  • Gunicorn: Manages a pool of pre-forked worker processes executing Python code.

2. Production Dependencies

Bash / Terminal
# Production WSGI server
pip install gunicorn
 
# PostgreSQL database driver
pip install psycopg2-binary
 
# Database URL parser for cloud platforms (DATABASE_URL)
pip install dj-database-url
 
# Static file serving for single-container cloud environments
pip install whitenoise

3. Configuring WhiteNoise for Static Assets

On platforms like Heroku or single-container Docker setups without a separate Nginx container, WhiteNoise allows Django to serve its own static files efficiently with gzip/brotli compression and caching:

Python
# config/settings.py
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware", # Place directly after SecurityMiddleware!
# ...
]
 
# Enable WhiteNoise compression and caching
STATIC_ROOT = BASE_DIR / "staticfiles"
STATIC_URL = "/static/"
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

4. Production Dockerfile

DOCKERFILE
# Use lightweight official Python image
FROM python:3.11-slim
 
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
 
WORKDIR /app
 
# Install system dependencies (for psycopg2 and build tools)
RUN apt-get update && apt-get install -y --no-install-recommends build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
 
# Install Python packages
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
 
# Copy application source code
COPY . .
 
# Collect static files at build time
RUN python manage.py collectstatic --noinput
 
# Expose production port
EXPOSE 8000
 
# Run Gunicorn with 3 pre-forked worker processes
CMD ["gunicorn", "--workers=3", "--bind=0.0.0.0:8000", "config.wsgi:application"]

5. Heroku Deployment via Procfile

For deploying to Heroku or Railway, specify process commands in a Procfile:

Output
release: python manage.py migrate
web: gunicorn config.wsgi:application --workers 3 --log-file -

The release phase runs database migrations automatically before traffic is switched to the newly deployed container, preventing downtime.


Interactive Quiz

Practice Quiz

Question 1
Why is Gunicorn required to serve Django applications in production instead of manage.py runserver?
Question 2
What does WhiteNoise enable for containerized Django deployments?
Question 3
How do you calculate the recommended number of Gunicorn worker processes?
Question 4
What does the command python manage.py collectstatic do?
Question 5
In a Heroku or Railway Procfile, what does the release phase do?
Next Lesson

Static & Media Files

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext