Back to Blog
Guide8 min read2026-05-01

Django Production Deployment: From Development to Production

A step-by-step guide to deploying Django applications to production using Docker, Gunicorn, and a managed cloud PaaS with PostgreSQL.

Django Production Deployment: From Development to Production

Django is a batteries-included Python web framework built for rapid development, but deploying it correctly to production requires several deliberate steps that go beyond running python manage.py runserver. This guide walks through a complete, production-ready Django deployment using Docker and [PandaStack](https://pandastack.io).

Why Django Needs Special Attention in Production

Django's development server is not suitable for production — it is single-threaded, not hardened against security threats, and not designed to handle concurrent traffic. In production, Django runs behind a WSGI server like Gunicorn, which manages worker processes and handles concurrent requests efficiently.

Additionally, Django's DEBUG = True mode exposes sensitive information in error pages and should never run in production.

Project Structure

A typical production Django project should look like this:

myproject/
├── myproject/
│   ├── settings/
│   │   ├── base.py
│   │   ├── development.py
│   │   └── production.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── requirements.txt
├── Dockerfile
└── pandastack.json

Splitting settings into base and environment-specific files prevents production configuration from mixing with development defaults.

Production Settings

# myproject/settings/production.py
from .base import *
import os

DEBUG = False
ALLOWED_HOSTS = [os.environ['ALLOWED_HOST']]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['DB_NAME'],
        'USER': os.environ['DB_USER'],
        'PASSWORD': os.environ['DB_PASSWORD'],
        'HOST': os.environ['DB_HOST'],
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

STATIC_ROOT = '/app/staticfiles'
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

SECRET_KEY = os.environ['DJANGO_SECRET_KEY']

Writing a Production Dockerfile

FROM python:3.12-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV DJANGO_SETTINGS_MODULE=myproject.settings.production

RUN apt-get update && apt-get install -y --no-install-recommends     build-essential libpq-dev     && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

RUN python manage.py collectstatic --noinput

EXPOSE 8000

CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

Your requirements.txt should include:

django>=5.0
gunicorn>=21.0
psycopg2-binary>=2.9
whitenoise>=6.6

Configuring pandastack.json

Add a pandastack.json at your project root for PandaStack to detect your health check endpoint:

{
  "type": "container",
  "healthCheckPath": "/health/"
}

Add a corresponding health check view:

# myproject/urls.py
from django.http import JsonResponse
from django.urls import path, include

def health_check(request):
    return JsonResponse({'status': 'ok'})

urlpatterns = [
    path('health/', health_check),
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')),
]

Provisioning a PostgreSQL Database

PandaStack provides managed PostgreSQL instances you can provision directly from [dashboard.pandastack.io](https://dashboard.pandastack.io). Navigate to Databases → New Database → PostgreSQL. Once provisioned, copy the connection details and set them as environment variables in your project:

DB_HOST=pg.internal.pandastack.io
DB_NAME=myapp_prod
DB_USER=myapp_user
DB_PASSWORD=your-secure-password
DJANGO_SECRET_KEY=your-50-char-secret
ALLOWED_HOST=yourdomain.com

Running Migrations

Django migrations must run before or alongside your application start. The cleanest pattern is a startup script:

#!/bin/sh
# entrypoint.sh
set -e

python manage.py migrate --noinput
exec "$@"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

Deploying via GitHub Integration

Connect your GitHub repository from the PandaStack dashboard. Every push to your production branch triggers an automatic build and deploy. Alternatively, use the CLI:

npm install -g @pandastack/cli
panda deploy

Static Files with WhiteNoise

For serving static files directly from Django without a separate CDN configuration, add WhiteNoise middleware:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ... rest of middleware
]

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Production Checklist

  • DEBUG = False in production settings
  • SECRET_KEY is stored as an environment variable
  • Database migrations run on startup
  • Static files are collected via collectstatic
  • Gunicorn workers are tuned to (2 × CPU cores) + 1
  • healthCheckPath returns HTTP 200

Handling Static Files in Production

Django's development server serves static files automatically, but in production with DEBUG = False, it does not. You have two options: use WhiteNoise (simplest, no extra server needed) or serve static files from a CDN.

WhiteNoise is the recommended approach for container deployments because it requires no external configuration. Add it to your middleware and storage settings as described above, run collectstatic during the Docker build, and your app serves compressed, cache-busted static assets directly from Gunicorn workers.

Logging Configuration

Django's default logging in production should output to stdout for PandaStack to capture in the dashboard:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'WARNING',
    },
}

This ensures errors surface in your deployment logs without requiring log file access inside the container.

For full deployment documentation, visit [docs.pandastack.io](https://docs.pandastack.io).

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Guide

Browse all Guide articles →

See also