An example project built with Django REST Framework and Celery.
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
"DEBUG" |
Logging threshold. Any value other than DEBUG disables Swagger UI and Django debug mode. |
API_HOST |
localhost; app |
Semicolon-separated list of hostnames that Django should accept (for example: d1.example.com; d2.example.com). |
DJANGO_SECRET_KEY |
Randomly generated | Django secret key. Set explicitly to keep sessions valid across restarts. |
POSTGRES_HOST |
"localhost" |
PostgreSQL host name. |
POSTGRES_PORT |
5432 |
PostgreSQL port. |
POSTGRES_USER |
"app_user" |
Database user. |
POSTGRES_DB |
"app_db" |
Database name. |
POSTGRES_PASSWORD |
"pass" |
Password for POSTGRES_USER. |
CELERY_BROKER_URL |
redis://redis:6379/0 |
Broker connection string (Redis). |
CACHE_URL |
redis://redis:6379/2 |
Redis instance used for Django cache. |
CELERY_RESULT_BACKEND |
redis://redis:6379/1 |
Redis instance used for storing Celery task results. |
CELERY_TASK_RESULT_EXPIRES |
3600 |
Lifetime of Celery task results in seconds. Once expired, AsyncResult returns None. |
CELERY_BROKER_POOL_LIMIT |
10 |
Maximum number of simultaneous broker connections kept in Celery’s connection pool. |
CELERY_BROKER_CONNECTION_TIMEOUT |
30 |
Seconds to wait for a broker connection before failing. |
CELERY_BROKER_CONNECTION_MAX_RETRIES |
0 |
Number of reconnection attempts after a broker failure. 0 means retry forever; None lets Celery use its default setting. |
CELERY_BEAT_SCHEDULE_FILENAME |
/data/celerybeat-schedule.db |
Path to the file where celery beat stores the schedule when running with DatabaseScheduler. |
CELERY_BROKER_HEARTBEAT |
30 |
Heartbeat interval (seconds) used to keep the broker connection alive and detect drops. |
FOLLOWUP_REPEAT_THRESHOLD |
1440 |
Minutes to suppress a repeat follow-up notification after the previous one was sent. |
TASK_LOCK_TIMEOUT |
60 |
Expiration (seconds) for the database lock used by the singleton_task decorator; after this delay a stale lock is considered abandoned. |
NIX_DAPHNE_PORT |
8081 |
Port used for web communication with the Django project. Used when starting daphne, only in the Nix Flakes build. |
Configuration files for Docker and Nix builds - env.list.
If you want to run Django locally like python manage.py runserver 0.0.0.0:8000, you can use local_env.list:
set -a
source ./local_env.list
set +aDocker Compose spins up the web app, Celery workers, PostgreSQL, and Redis in one network. Install Docker and Docker Compose before continuing.
Start the database and Redis services:
docker compose up -d postgres redisRun initial database migrations:
docker compose run --rm app python3 manage.py migrateLaunch the web app, Celery worker, and beat scheduler in the foreground:
docker compose up app worker beatRun the same stack in the background:
docker compose up -d app worker beatRebuild containers after dependency updates:
docker compose up --build app worker beatRun the Django test suite for the lead app:
docker compose run --rm app python3 manage.py test leadCreate an admin user:
docker compose run --rm app python3 manage.py createsuperuserNix provides an alternative stack that mirrors the Docker Compose.
Install Nix before continuing.
The flake expects the nix-command and flakes experimental features to be enabled.
Either set them globally (e.g. add experimental-features = nix-command flakes to ~/.config/nix/nix.conf)
or pass --extra-experimental-features 'nix-command flakes' to each command shown below.
All flake outputs live in the nix/ directory. Prefix the commands with
./nix (as in the examples) if you keep the repo layout unchanged.
Enter a development shell with Python, PostgreSQL, Redis, uv, and helper tools:
nix --extra-experimental-features 'nix-command flakes' develop ./nixLaunch the entire stack (web, worker, beat, PostgreSQL, Redis) in the foreground:
nix --extra-experimental-features 'nix-command flakes' run ./nix#stackOr in Docker Compose Like mode:
nix --extra-experimental-features 'nix-command flakes' run ./nix#stack -- --tui=falseLogs are multiplexed by process-compose; press q to exit while leaving services
stopped cleanly.
Both commands reuse env.list. Host names such as postgres and redis are rewritten to 127.0.0.1 automatically for the Nix setup.
My Nix Flakes build script is far from ideal. If something goes wrong and I'm left with child processes:
./nix/scripts/kill-services.shIf you see something like this in the logs:
app-1 | 2025-09-20 21:00:36 | WARNING | django.security.SuspiciousSession (base) | Session data corrupted
Clear your browser's cookies for the domain where the application is running (or on localhost if you haven't changed anything).
To prevent this error, set DJANGO_SECRET_KEY. One way to generate it is:
echo "DJANGO_SECRET_KEY=\"$(openssl rand -base64 50 | tr -d '\n')\""Nix Flakes uses process-compose, which by default occupies port 8080 with its Web service. I chose 8081 as the default for daphne inside Nix. Not 80, because in WSL2, where I was developing, it requires root access.
