Django GitHub Actions Workflow Template
Last updated
This is a working .github/workflows/ci.yml for a Django project that tests against a real Postgres database. It starts Postgres as a service container, caches pip, checks for missing migrations and runs your tests.
The workflow
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 20
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/app_test
DJANGO_SETTINGS_MODULE: config.settings
SECRET_KEY: ci-only-not-a-secret
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
cache-dependency-path: requirements*.txt
- run: pip install -r requirements.txt
- run: python manage.py makemigrations --check --dry-run
- run: python manage.py test --parallel
What the non-obvious parts do
services.postgresstarts a Postgres container beside the job. Because the job runs directly on the runner, it reaches the database atlocalhost:5432, andportspublishes it.- The
optionshealth check makes GitHub wait untilpg_isreadysucceeds before running steps. Without it, the first step that touches the database can fail at random, a common cause of flaky tests. DATABASE_URLassumes you parse it withdj-database-urlor similar. If your settings readDB_HOST,DB_NAMEand so on, set those instead.DJANGO_SETTINGS_MODULEandSECRET_KEYare placeholders. Change the module path to yours. A throwaway key is fine in CI; never reuse a production secret here.makemigrations --check --dry-runfails the build if a model change is missing its migration file.test --parallelruns test processes in parallel and clones the test database for each one. Postgres is fine with this. If your tests use pytest, runpytest -n autoinstead (needspytest-djangoandpytest-xdist).cache: pipcaches downloads, keyed on the requirements files. See caching pip.
Variants
Python version matrix
Add strategy.matrix.python: ["3.11", "3.12", "3.13"] and use ${{ matrix.python }}. Keep the quotes. See matrix builds.
Redis or Celery
Add a redis service the same way, with redis:7 and --health-cmd "redis-cli ping".
Static files and linting
Add ruff check . before the tests and python manage.py collectstatic --noinput if your tests render pages that need the manifest.
Deploy job
Add a second job with needs: test that runs only on main. Use OIDC for cloud credentials.
Run it on faster machines
Django suites that hit the database are CPU and disk bound. Change one line:
runs-on: [self-hosted, Linux, compiler-ci]
The job runs on a fresh 8 vCPU machine from compiler.dev, with fallback to your original runner. The service container works the same way. Tuning tips are in speed up Django on GitHub Actions; see also pricing.
FAQ
Do I need a service container, or can I use SQLite?
SQLite is quicker but hides Postgres-specific behaviour. If production runs Postgres, test on Postgres.
Why does the test database connection fail intermittently?
Usually a missing health check. Keep the options block.
How do I split a slow Django test suite?
Use --parallel for cores and test sharding across jobs, with a separate database per shard.
Can I run this on Windows or macOS?
Service containers only work on Linux runners. Stay on Linux for database tests.
Related
- Speed Up Django in GitHub ActionsSpeed up Django tests in GitHub Actions with pip or uv caching, pytest-xdist, --reuse-db, a Postgres service, and test splitting. Working YAML.
- .NET GitHub Actions Workflow TemplateCopy-paste GitHub Actions CI for .NET with NuGet caching, restore, build and test steps, a SQL Server service option, concurrency and permissions.
- Docker Build GitHub Actions Workflow TemplateCopy-paste GitHub Actions workflow to build Docker images with Buildx, GitHub cache layers and a push to GHCR on main, with minimal permissions.
- Elixir GitHub Actions Workflow TemplateCopy-paste GitHub Actions CI for Elixir and Phoenix with a Postgres service, deps and _build caching via erlef/setup-beam, plus format and tests.