Django Dockerfile for ASGI with Uvicorn (Production, Slim)
This Django Dockerfile serves your project through ASGI with Uvicorn on python:3.13-slim, which unlocks async views and long-lived connections. Dependencies are installed in a separate stage and static files are collected at build time. The app runs as a non-root user on port 8000.
- CI status
- Build passing
- Image size (uncompressed)
- 155 MB
- Build time
- 14 s
- Runtime image
python:3.13-slim- Port
- 8000
- Last built
- 2026-10-15
# syntax=docker/dockerfile:1
FROM python:3.13-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.13-slim
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 DJANGO_SETTINGS_MODULE=config.settings
WORKDIR /app
COPY --from=builder /install /usr/local
COPY . .
RUN SECRET_KEY=build-only python manage.py collectstatic --noinput \
&& useradd --create-home --uid 10001 app
USER app
EXPOSE 8000
CMD ["uvicorn", "config.asgi:application", "--host", "0.0.0.0", "--port", "8000"].git
__pycache__/
*.pyc
.venv/
.env
media/
staticfiles/
db.sqlite3
Dockerfile
.dockerignoreBefore you build
- Name your project module config so config.asgi and config.settings resolve, or adjust both references.
- Set STATIC_ROOT in settings so collectstatic has a destination.
- Read SECRET_KEY from the environment.
- Add uvicorn to requirements.txt.
- Serve the collected static files through your reverse proxy or WhiteNoise.
How this Dockerfile works
FROM python:3.13-slim AS builderPackages are installed in a disposable stage, so the final image contains only what the app needs to run.
RUN pip install --no-cache-dir --prefix=/install -r requirements.txtInstalls Django, Uvicorn and your other dependencies into one directory without keeping pip's download cache.
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 DJANGO_SETTINGS_MODULE=config.settingsTurns off .pyc files, streams logs immediately, and tells Django which settings module to load inside the container.
RUN SECRET_KEY=build-only python manage.py collectstatic --noinput \Collects static files once at build time. The placeholder SECRET_KEY only satisfies settings for this command and never reaches runtime.
&& useradd --create-home --uid 10001 app USER appCreates an unprivileged user in the same layer and switches to it before the server starts.
CMD ["uvicorn", "config.asgi:application", "--host", "0.0.0.0", "--port", "8000"]Starts Django's ASGI application under Uvicorn on all interfaces. Async views run on the event loop, and sync views run in a thread pool.
Build and run
docker build -t django-app .
docker run --rm -p 8000:8000 -e SECRET_KEY=change-me django-appSupply the real SECRET_KEY, database URL and ALLOWED_HOSTS as environment variables at runtime, then open http://localhost:8000 to check the server responds.
Other Django Dockerfile variants
Gunicorn with WSGI workers remains the most common choice for classic request/response Django apps. ASGI with Uvicorn suits projects that use async views, server-sent events or WebSockets via Channels. Both are listed in the table below.
| Variant | Runtime image | Image size | CI |
|---|---|---|---|
| Python slim + Gunicorn (multi-stage) | python:3.13-slim | 155 MB | Passing |
| Python slim + Uvicorn (ASGI) | python:3.13-slim | 155 MB | Passing |
Troubleshooting
- SynchronousOnlyOperation: You cannot call this from an async context
- An async view calls the ORM directly. Use the async ORM methods, such as aget and acreate, or wrap the call with sync_to_async.
- ImproperlyConfigured: STATIC_ROOT setting is missing during the build
- collectstatic needs a destination directory. Set STATIC_ROOT in settings, for example to a staticfiles folder inside the project, and rebuild.
- DisallowedHost error on the first request
- Add the host name you browse to, such as localhost or your domain, to ALLOWED_HOSTS, ideally read from an environment variable.
FAQ
- Do I need ASGI if my views are all synchronous?
- No. Synchronous Django runs well under Gunicorn. ASGI pays off once you add async views, streaming responses or WebSockets.
- Can I run several Uvicorn workers?
- Yes. Add --workers to the Uvicorn command, or scale by running more containers. Each worker is a separate process with its own memory.
- Where should migrations run?
- Run them as a one-off step in your deploy pipeline using the same image, not on container start, so replicas don't race to migrate.