django-baseshift-brancher
Run your Django test suite against an already-migrated PostgreSQL clone, so tests don't need to run CREATE DATABASE or migrations on every run.
On a large Django project, a lot of test time goes to building the test database and replaying every migration. django-baseshift-brancher skips both steps. It uses brancher by Baseshift to create one ready-to-use PostgreSQL clone per test worker, already migrated to the schema of your current git checkout. Then it points pytest or Django's test runner at those clones.
- Works with pytest / pytest-django (
pytest -n N) and Django'smanage.py test(--parallel N) - No changes to
settings.py - Migrated snapshots are cached per migration commit and shared across branches
Requirements
| Requirement | Version |
|---|---|
| Python | 3.8 – 3.13 |
| Django | 3.2, 4.2, 5.0 – 6.0 |
| Database | PostgreSQL |
| brancher by Baseshift | The baseshift binary must be on your PATH (install brancher) |
| Git | Your project must be a git repository |
Install
pip install django-baseshift-brancher
# If pytest-django isn't installed yet:
pip install "django-baseshift-brancher[pytest]"
Quick start
Run these from your Django project root (the directory that contains manage.py).
1. Create the clones
export DJANGO_SETTINGS_MODULE=yourproject.settings
unset BASESHIFT_BRANCHES_FILE DATABASE_URL PGHOST PGPORT
django-baseshift-brancher clone --count 4
--count is the number of databases to create. You need one per test worker.
The command writes the clone details to .brancher/clones.json, prints them as JSON, and prints the export line you need next (on stderr).
2. Run the tests
pytest
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"
pytest -n 4
Django test runner
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"
python manage.py test --testrunner django_baseshift_brancher.DiscoverRunner --parallel 4
3. Clean up
baseshift stop --all
How it works
Snapshots follow your migration history
clone reads your git history. Every commit that changes migration files gets its own migrated snapshot.
- Adding migration files builds on the previous snapshot. Branches that split off from the same migration commit share it.
- Changing or deleting existing migration files starts over from an empty snapshot, because the new schema can't be built on top of the old one.
- Rebasing creates new commits, so the rebased checkout gets a new snapshot on top of its new parent. Branches that split off before the rebase keep their own chain.
Snapshots don't have names and you never manage them yourself. Parent snapshots are picked automatically.
Test workers map to clones
| Runner | Worker ID | Clone used |
|---|---|---|
| pytest-xdist | gw0, gw1, … (0-based) |
gw0 → 1st clone |
Django --parallel |
"1", "2", … (1-based) |
"1" → 1st clone |
pytest -n 4 and --parallel 4 each need --count 4 (or more).
What happens to your DATABASES setting
USERandPASSWORDare kept as you configured them.HOST,PORTandNAMEare replaced with the clone's values.- Test migrations are turned off (the clone is already migrated).
pytest plugin
The plugin loads automatically. It assigns each worker to a clone and forces --reuse-db and --no-migrations. Don't pass --create-db.
Configuration
| Environment variable | Required | Purpose |
|---|---|---|
DJANGO_SETTINGS_MODULE |
Yes | Your Django settings module |
BASESHIFT_BRANCHES_FILE |
Yes, when running tests | Absolute path to .brancher/clones.json. Tests only read the clones from this variable. A clones.json in the current directory is not picked up automatically. |
BASESHIFT_INIT_SQL |
No | SQL that runs on each new snapshot before migrate. Use it for anything your migrations assume already exists, such as extensions. |
Example:
export BASESHIFT_INIT_SQL="CREATE EXTENSION IF NOT EXISTS pg_trgm"
Other setup commands: once the clones are running, run any extra project setup yourself against their connection strings (for example, a management command like ensure_celery_broker_schema).
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Tests connect to your normal dev/CI database | BASESHIFT_BRANCHES_FILE isn't set in the shell running the tests |
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json" |
| Some workers fail or no clone is found for them | Fewer clones than workers | Re-run clone with --count ≥ -n / --parallel |
| Tests try to create the database | --create-db was passed |
Remove --create-db |
| A migration fails with a missing extension | The extension has to exist before migrations run | Set BASESHIFT_INIT_SQL and re-run clone |
baseshift: command not found |
brancher isn't installed | Install it from baseshift.com/brancher |
For AI coding agents
Use this exact sequence from the Django project root. Replace N with the number of parallel test workers.
export DJANGO_SETTINGS_MODULE=<project>.settings
unset BASESHIFT_BRANCHES_FILE DATABASE_URL PGHOST PGPORT
django-baseshift-brancher clone --count N
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"
pytest -n N # or: python manage.py test --testrunner django_baseshift_brancher.DiscoverRunner --parallel N
baseshift stop --all
Rules:
- Don't edit
settings.py. - Don't pass
--create-db. - Re-run
cloneafter checking out a commit with different migrations. BASESHIFT_BRANCHES_FILEmust be exported in the same shell that runs the tests.- Always run
baseshift stop --allwhen you're done.
About Baseshift
Baseshift gives every developer, coding agent and pull request its own isolated, writable, masked clone of your real database, running in your cloud and ready in seconds. It supports PostgreSQL, MySQL, MongoDB and MariaDB. It also adds guardrails for database changes, such as schema change detection and query risk checks, so issues are caught before they reach production.
This package is the Django integration for brancher by Baseshift.
License
Proprietary. See baseshift.com for terms.
Metadata
Release files for django-baseshift-brancher 0.13.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_baseshift_brancher-0.13.0.tar.gz | 53.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_baseshift_brancher-0.13.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 94.3 kB
Release files / django_baseshift_brancher-0.13.0.tar.gz
| Download URL | django_baseshift_brancher-0.13.0.tar.gz |
|---|---|
| Size | 53.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ff8dec5673943fdf4392923ab1bfba24120ac9c95a4fbbf0fbb2a9a99131dc56
|
|
BLAKE2b-256 checksum How to use checksums |
18827176c93fb7e889eccd8a9e51005f7768b866de852b06f2592b9918ac140c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / django_baseshift_brancher-0.13.0-py3-none-any.whl
| Download URL | django_baseshift_brancher-0.13.0-py3-none-any.whl |
|---|---|
| Size | 41.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c91865c1e86251558bf7b407f188dab15bcb8ce1ce14214911a5c587618ca4c7
|
|
BLAKE2b-256 checksum How to use checksums |
e88e815df3318e903e68b43c5b8f0cd2f92cdde906348017c6dbc7d60d203cd3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|