Deployment
#django
#render
#postgresql

How to Deploy Django on Render

It is easy to get a Django app running on Render, but it is also easy to ship an unsafe or incomplete production setup.

Problem statement

It is easy to get a Django app running on Render, but it is also easy to ship an unsafe or incomplete production setup.

The common failures are predictable:

  • DEBUG left enabled
  • SECRET_KEY committed to Git
  • missing ALLOWED_HOSTS or CSRF_TRUSTED_ORIGINS
  • PostgreSQL not configured from environment variables
  • static files not collected or not served correctly
  • migrations forgotten during deployment
  • app code deployed successfully, but the database schema is still old

If you want to deploy Django on Render safely, you need a setup that covers the app server, database, static files, secrets, HTTPS-aware settings, and verification after release.

Quick answer

The shortest correct path to deploy Django on Render is:

  1. Prepare your Django app for production
  2. Add gunicorn, a PostgreSQL driver, and optionally dj-database-url and whitenoise
  3. Create a PostgreSQL database on Render
  4. Create a Python web service connected to your Git repository
  5. Set environment variables such as SECRET_KEY, DATABASE_URL, and host/CSRF settings
  6. Use Gunicorn as the start command
  7. Run collectstatic during build
  8. Apply migrations as part of the release process before treating the deploy as healthy
  9. Verify homepage, admin, database writes, and static files

You can do this either:

  • manually in the Render dashboard
  • with a render.yaml blueprint for repeatable setup

Step-by-step solution

1. Prepare your Django app for Render

Add production dependencies

Install the common packages used for a Django deployment on Render:

pip install gunicorn dj-database-url whitenoise psycopg[binary]
pip freeze > requirements.txt

If your project already uses a lockfile workflow, keep using that. The important part is that Render can install the exact dependencies during build.

Configure production settings

A minimal production-safe settings pattern looks like this:

import os
from pathlib import Path
import dj_database_url

BASE_DIR = Path(__file__).resolve().parent.parent

DEBUG = os.environ.get("DEBUG", "False").lower() == "true"

SECRET_KEY = os.environ["SECRET_KEY"]

ALLOWED_HOSTS = [
    "your-service.onrender.com",
    "yourdomain.com",
]

CSRF_TRUSTED_ORIGINS = [
    "https://your-service.onrender.com",
    "https://yourdomain.com",
]

DATABASES = {
    "default": dj_database_url.parse(
        os.environ["DATABASE_URL"],
        conn_max_age=600,
    )
}

SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True

SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = False

If you prefer ALLOWED_HOSTS from environment variables, that is fine too. Just make sure the Render hostname and any custom domain are included.

A safe parsing pattern is:

ALLOWED_HOSTS = [h for h in os.environ.get("ALLOWED_HOSTS", "").split(",") if h]
CSRF_TRUSTED_ORIGINS = [o for o in os.environ.get("CSRF_TRUSTED_ORIGINS", "").split(",") if o]

If you enable HSTS, do it only after HTTPS is confirmed to work correctly on every intended domain.

Make static files work on Render

If you want Django to serve static files directly, WhiteNoise is the simplest starting point.

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    # other middleware...
]

STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"

STORAGES = {
    "staticfiles": {
        "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
    },
}

Then collect static files:

python manage.py collectstatic --noinput

For many apps, WhiteNoise is enough. If your static or media workload grows, object storage is usually the better next step, especially for user-uploaded files.

Verify locally in production mode

Before deploying, test with production-like settings locally:

export DEBUG=False
export SECRET_KEY='replace-me'
export DATABASE_URL='postgresql://user:pass@localhost:5432/mydb'
python manage.py collectstatic --noinput
python manage.py migrate
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000

Check:

  • app boots without Django debug mode
  • static files resolve
  • database connection works
  • no settings rely on local-only assumptions

2. Create the supporting services on Render

Create a PostgreSQL database

In Render, create a managed PostgreSQL database first.

Choose:

  • the same region as the web service
  • an appropriate plan for your environment
  • backup expectations that match your recovery needs

Once created, Render provides a connection string you can use as DATABASE_URL.

Verification check:

  • confirm the database status is healthy
  • confirm you can reference its connection string from your app service

Decide between dashboard setup and render.yaml

Manual dashboard setup is fine for a first deployment or a single environment.

Use render.yaml when you want:

  • repeatable environment creation
  • lower config drift
  • service definitions stored in Git

For teams or multiple environments, blueprint-based deployment is usually easier to maintain.

3. Deploy Django on Render from the dashboard

Connect the repository

Create a new Web Service in Render and connect your GitHub or GitLab repository.

Choose:

  • the correct branch
  • Python as the environment

Configure the web service

Use a build command that installs dependencies and collects static files:

pip install -r requirements.txt && python manage.py collectstatic --noinput

Use a start command that runs Gunicorn on Render’s assigned port:

gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT

Also make sure:

  • the web service region matches the database region
  • the instance type is appropriate for your app size

Verification check:

  • build logs should show dependency installation and successful collectstatic
  • startup logs should show Gunicorn booting cleanly

Set environment variables

In the Render dashboard, add at least:

  • SECRET_KEY
  • DEBUG=False
  • DATABASE_URL
  • any app-specific secrets
  • optionally host lists if you load them from environment

Do not hardcode secrets in the repository.

If you manage host settings via environment variables, a common pattern is:

ALLOWED_HOSTS = [h for h in os.environ.get("ALLOWED_HOSTS", "").split(",") if h]
CSRF_TRUSTED_ORIGINS = [o for o in os.environ.get("CSRF_TRUSTED_ORIGINS", "").split(",") if o]

Then set values like:

  • ALLOWED_HOSTS=your-service.onrender.com,yourdomain.com
  • CSRF_TRUSTED_ORIGINS=https://your-service.onrender.com,https://yourdomain.com

Configure migrations and static file collection

collectstatic fits naturally in the build step. Migrations need more care.

Do not let a new release depend on manual post-deploy migrations. Run:

python manage.py migrate

as part of a controlled release step before treating the deployment as healthy. If you cannot automate that safely yet, restrict production use until migration completion is verified, and prefer backward-compatible migrations.

Rollback note: application code is easier to roll back than database schema. Prefer additive, backward-compatible migrations where possible.

Add a health check path

Configure a simple health endpoint that does not require login, for example /healthz/, and point Render health checks to it if your service setup uses custom health check paths.

A minimal Django view can be as simple as:

from django.http import HttpResponse

def healthz(request):
    return HttpResponse("ok", content_type="text/plain")

And in urls.py:

from django.urls import path
from .views import healthz

urlpatterns = [
    path("healthz/", healthz),
]

Verification check:

  • /healthz/ returns 200
  • it does not depend on session state or admin login
  • it still works after a fresh deploy

4. Deploy Django on Render with render.yaml

A simple blueprint can define both the web service and database:

services:
  - type: web
    name: my-django-app
    env: python
    buildCommand: pip install -r requirements.txt && python manage.py collectstatic --noinput
    startCommand: gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT
    envVars:
      - key: SECRET_KEY
        generateValue: true
      - key: DEBUG
        value: "False"
      - key: DATABASE_URL
        fromDatabase:
          name: my-django-db
          property: connectionString

databases:
  - name: my-django-db

This is useful because the deployment definition lives with the application code. That reduces manual drift across environments.

5. Run the first production deployment

Trigger the deploy and watch the logs.

You want to see:

  • dependencies installed successfully
  • collectstatic complete without errors
  • Gunicorn starting without import or settings failures

Ensure migrations are applied as part of the release process:

python manage.py migrate

If you need Django admin access, create a superuser:

python manage.py createsuperuser

Use this as a controlled one-time setup step. Over time, many teams replace interactive production admin setup with scripted or managed workflows.

Verification check:

  • homepage returns 200
  • /admin/ loads
  • login works
  • a database-backed page can read and write data
  • static assets load without 404
  • /healthz/ returns 200

6. Configure a custom domain and HTTPS

Attach the custom domain in Render and update your DNS records as instructed in the Render dashboard. DNS changes may take time to propagate.

After that, update Django:

ALLOWED_HOSTS = ["your-service.onrender.com", "yourdomain.com"]
CSRF_TRUSTED_ORIGINS = ["https://your-service.onrender.com", "https://yourdomain.com"]

If you use www, add both hostnames and both trusted origins.

With Render terminating HTTPS in front of your app, these settings matter:

SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Verification check:

  • custom domain resolves
  • HTTPS loads correctly
  • forms submit without CSRF errors
  • redirects do not loop

Explanation

This setup works because it matches how Django should run behind a managed platform proxy:

  • Gunicorn serves the Django WSGI app
  • Render provides the runtime and public endpoint
  • PostgreSQL is injected through DATABASE_URL
  • WhiteNoise handles static assets if you are not using external storage
  • Django is made proxy-aware with SECURE_PROXY_SSL_HEADER
  • secrets stay outside the repository in environment variables

Manual dashboard setup is good for getting started. render.yaml is better when you want repeatable infrastructure and fewer manual mistakes.

When manual Render setup becomes repetitive

Once you are deploying multiple environments or multiple projects, the same steps repeat: service creation, environment variable setup, build commands, migration checks, health checks, and smoke tests. That is the point where a reusable render.yaml, a hardened settings module, and a release checklist become worthwhile. Automating those parts reduces config drift more than it reduces effort.

Edge cases / notes

  • Static vs media files: WhiteNoise is for static files, not user-uploaded media. If users upload files, plan external object storage.
  • DisallowedHost errors: usually caused by missing Render hostname, custom domain, or www variant in ALLOWED_HOSTS.
  • CSRF failures after adding a domain: update CSRF_TRUSTED_ORIGINS with full https:// origins.
  • Missing DATABASE_URL: fail fast in production. Do not silently fall back to SQLite or an incomplete database config.
  • Migration risk: a bad migration can break a healthy app. Prefer additive, backward-compatible schema changes.
  • Rollback: if a code change fails, redeploy the previous commit. If an environment variable change caused the issue, restore the previous value. Database rollback is harder and may require restoring from backup or applying corrective migrations.
  • Health checks: keep the endpoint simple. Do not require authentication, and do not make it expensive to compute.
  • Gunicorn tuning: the basic start command is enough to begin. Tune workers and timeouts later based on real traffic and memory use.

For the settings side of this deployment, see the Django deployment checklist for production.

If you want to compare Render with a self-managed server approach, read Deploy Django with Gunicorn and Nginx on Ubuntu.

For more detail on static file handling, see how to configure Django static files in production.

For recovery planning after a bad release, read how to roll back a Django deployment safely.

FAQ

Can I deploy Django on Render without Docker?

Yes. Render supports Python web services directly, so Docker is not required for a standard Django deployment.

Do I need Gunicorn on Render for Django?

Yes, for a typical Django deployment you should run Gunicorn as the app server:

gunicorn myproject.wsgi:application --bind 0.0.0.0:$PORT

How do I run migrations on Render safely?

Run python manage.py migrate as part of a controlled release process, not as an afterthought once the new code is already serving traffic. Prefer backward-compatible migrations so old and new app versions can tolerate the same schema during rollout.

Why are my static files not loading on Render?

Usually one of these is missing:

  • STATIC_ROOT
  • collectstatic during build
  • WhiteNoise middleware and storage config
  • correct static file references in templates

Should I use render.yaml or configure services manually?

Use manual dashboard setup for a first deployment or a single app. Use render.yaml when you want repeatability, versioned infrastructure, and lower config drift.

2026 · django-deployment.com - Django Deployment knowledge base