> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slipway.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy a Django app

> Deploy a Django app with Postgres and run migrations on every deploy.

Django runs on slipway as a `web` service on the Python runtime, with a managed Postgres
alongside it.

## Prerequisites

A Django project in a GitHub or GitLab repository, with `gunicorn` in your requirements.

## Configure the app

Django rejects requests whose `Host` header is not in `ALLOWED_HOSTS`, which otherwise shows
up as a 403 on a deploy that looks healthy.

```python settings.py theme={"system"}
import os

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

CSRF_TRUSTED_ORIGINS = [
    f"https://{h}" for h in ALLOWED_HOSTS if h and "*" not in h
]

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

## Add slipway.yaml

```yaml slipway.yaml theme={"system"}
version: 1

databases:
  - name: db
    engine: postgres
    version: "18"
    diskSizeGB: 10

services:
  - name: web
    runtime: python
    runtimeVersion: "3.12"
    buildCommand: pip install -r requirements.txt
    command: ["gunicorn", "myproject.wsgi", "--bind", "0.0.0.0:8000"]
    preDeploy: ["python", "manage.py", "migrate", "--noinput"]
    dependsOn: [db]
    ports:
      - port: 8000
        public: true
    healthCheckPath: /healthz/
    env:
      DATABASE_URL: ${service.db.url}
      ALLOWED_HOSTS: ${service.web.host}
      SECRET_KEY: ${secret.DJANGO_SECRET_KEY}
      DEBUG: "0"
```

Replace `myproject` with your project package.

`preDeploy` runs migrations in the freshly built image before the rollout, and the deploy
proceeds only if it exits 0.

## Set the secret

Before the first deploy, add `DJANGO_SECRET_KEY` under the project's
**Settings → Variables & secrets**. A reference nothing satisfies leaves the key unset and
records a warning in the deploy log, so set the value first to start with it in place.

## Add a health check endpoint

```python urls.py theme={"system"}
from django.http import HttpResponse
from django.urls import path

urlpatterns = [
    path("healthz/", lambda r: HttpResponse("ok")),
]
```

Keep it cheap. A health check that queries the database fails the deploy whenever the
database is slow.

## Static files

For WhiteNoise, collect during the build:

```yaml slipway.yaml theme={"system"}
    buildCommand: pip install -r requirements.txt && python manage.py collectstatic --noinput
```

For user uploads, use [object storage](/data/object-storage) rather than the container
filesystem, which is lost on every deploy.

## Add a worker

```yaml slipway.yaml theme={"system"}
  - name: worker
    type: worker
    runtime: python
    runtimeVersion: "3.12"
    buildCommand: pip install -r requirements.txt
    command: ["celery", "-A", "myproject", "worker", "-l", "info"]
    env:
      DATABASE_URL: ${service.db.url}
      CELERY_BROKER_URL: ${service.queue.url}
```

With a Redis broker:

```yaml slipway.yaml theme={"system"}
databases:
  - name: queue
    engine: redis
```

## Next steps

> **[Postgres](/data/postgres)**
>
> Credentials, backups and external access.

> **[Troubleshooting](/deploys/troubleshooting)**
>
> What to check when a deploy goes wrong.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.