# Run two Claude Code coding sessions in separate Django worktrees
> Use two Claude Code sessions for approved Django coding tickets in separate Git worktrees. Verify distinct SQLite files and ports, then review and test the combined branch before cleanup.
By BIG CHANGE Editorial
Published: 2026-10-22T04:42:39.002Z
Updated: 2026-10-22T04:42:39.002Z
Canonical: https://bigchange.ai/blog/claude-code-django-parallel-worktrees-guide

AI-generated conceptual illustration by BIG CHANGE.
Two coding tickets can proceed at once in an existing Django repository, with one Claude Code session in each Git worktree. The branch split is the easy part. Before either session changes data, the developer must establish that each checkout uses its own SQLite file, local port and other mutable resources. The combined branch then needs a fresh database and its own test run before anyone decides to land it.
## The big change
- **What changed:** [Claude Code supports parallel sessions in Git worktrees](https://code.claude.com/docs/en/worktrees), so two bounded coding tasks can use separate branches and files from one repository. Their runtime dependencies still need separate configuration.
- **Why it matters:** A developer can review each ticket on its own branch while keeping the main checkout available. Distinct database paths and ports make each local result attributable to the right task; Git alone cannot provide that boundary.
- **What to watch:** The decision rests on the integrated migration path and both acceptance checks. A test that passes against one branch's database says little about the merged schema or the other ticket's behavior.
## Check the project before creating a worktree
This procedure is for a developer who owns an **existing**, authorized Git repository with at least one commit, a Django application configured for a local, file-backed SQLite development database, and two real, approved coding tickets. The developer needs authority to run local services, use Claude Code on the repository and review an integration branch. Each ticket needs a concrete expected result, relevant existing tests or a reproducible defect, and an agreed first set of files to own. Assign a human reviewer for the two changes and the merge.
The commands below use **Windows PowerShell** and Django **5.2** command syntax. Confirm the application's pinned Django version and its own setup and test commands first. Supply actual repository paths, branch names, tickets and test targets; the names below are placeholders. Nothing here is a record of a Django application or Claude Code run by BIG CHANGE.
Check the main checkout's status and record the approved base commit. Preserve any existing work there. Confirm that the two proposed branches do not already exist and the paths are available. Also inspect the repository's ignore rules, `.env` loading, Django settings, Claude project settings, hooks, plugins and MCP servers. [Anthropic documents shared repository and Claude configuration across worktrees](https://code.claude.com/docs/en/worktrees#what-worktrees-share-with-the-main-checkout). Separate checkouts do not isolate an absolute database path, external service, credentials or a server port.
Before starting two sessions, verify the installed Git, Python, Claude Code and Django versions. Confirm that the actual Claude account or provider permits the intended concurrent use and check its usage and spending controls. Give each tree only the local credentials its task needs. Keep production and staging database connections out of this workflow. If the application writes to a cache, queue, mail service, media directory or external API, give each ticket a safe local namespace or approved substitute; pause concurrent work when that cannot be done.
## 1. Create two branches from the same approved commit
In a PowerShell terminal at the main repository, use the real values approved for the project:
```powershell
git status --short --untracked-files=all
git rev-parse HEAD
git worktree list
git worktree add -b <ticket-a-branch> <absolute-path-a> <approved-base-commit>
git worktree add -b <ticket-b-branch> <absolute-path-b> <approved-base-commit>
git worktree list
git -C <absolute-path-a> status --short --branch
git -C <absolute-path-b> status --short --branch
```
The angle-bracket values above are placeholders: replace each **whole argument** with a real value before running the command. Quote a path containing spaces. Both branch heads should initially resolve to the approved commit. If Git refuses a branch or path, inspect `git worktree list`, the actual branch names and the path; do not force a second checkout of a branch already in use. [Git's worktree manual](https://git-scm.com/docs/git-worktree) documents `add -b`, `list` and the shared repository relationship.
## 2. Prove separate Python and SQLite state
Open one PowerShell terminal in each new worktree. Create a separate `.venv` in each and install **that repository's pinned dependencies** using its documented command. For a project whose pinned requirements file is `requirements.txt`, the commands would be:
```powershell
Set-Location <absolute-path-a>
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m django --version
```
Repeat in tree B with its path. Use the project's actual Python launcher and dependency manager when they differ. Do not copy a virtual environment, `.env`, SQLite file or secrets from the main checkout as a shortcut. Inspect local configuration without printing secret values. Record the settings module used in each terminal.
Before `migrate`, a server start or an agent write, inspect the **effective** database settings in each environment. With the tree's virtual environment active, the following Django 5.2 command prints the engine, rejects a non-SQLite, empty, in-memory or SQLite URI `NAME`, then prints the raw name and resolved file path. Keep this local path readback private:
```powershell
.\.venv\Scripts\python.exe manage.py shell -c "from django.conf import settings; from pathlib import Path; d=settings.DATABASES['default']; print('ENGINE:', d['ENGINE']); assert d['ENGINE']=='django.db.backends.sqlite3', 'Stop: expected SQLite'; raw=d['NAME']; assert raw is not None and str(raw) and str(raw)!=':memory:' and not str(raw).lower().startswith('file:'), 'Stop: expected a file-backed SQLite path'; print('NAME:', repr(raw)); print('RESOLVED:', Path(raw).resolve())"
```
Compare both outputs with the actual worktree paths. Proceed only when each resolved database path lies inside its own checkout and the paths differ. Inspect any additional database aliases and the test configuration the app uses. An absolute `NAME` outside its tree, a shared `.env` URL, an in-memory database, a SQLite URI or another engine needs an explicit, reviewed local isolation configuration first. A relative-looking value is insufficient evidence until resolved. Django's [database `NAME` setting](https://docs.djangoproject.com/en/5.2/ref/settings/#name) and [installation guide](https://docs.djangoproject.com/en/5.2/topics/install/) explain the SQLite setup; this path check is the operator's proof for the actual app.
Now run the project's baseline checks separately in A and B. On each **verified disposable** local database, inspect the migration plan, apply only the approved local migrations, then run the normal checks and relevant baseline tests:
```powershell
.\.venv\Scripts\python.exe manage.py migrate --plan
.\.venv\Scripts\python.exe manage.py migrate
.\.venv\Scripts\python.exe manage.py check
.\.venv\Scripts\python.exe manage.py test
```
Replace `manage.py test` with the repository's required runner and targets when appropriate. Record actual outcomes, including failures. [Django documents](https://docs.djangoproject.com/en/5.2/ref/django-admin/) `migrate --plan`, `check` and `test`; its test runner normally creates a separate test database. A passing test does not prove which development SQLite file a running server will use. Preserve any needed local data before recreating a database.
## 3. Start separate local servers and Claude Code sessions
Choose two available loopback ports. `127.0.0.1:8001` and `127.0.0.1:8002` are candidate values, not a claim that either is free. In the respective worktree terminals, after confirming the database readback:
```powershell
# Terminal A, current directory is tree A
.\.venv\Scripts\python.exe manage.py runserver 127.0.0.1:8001
```
```powershell
# Terminal B, current directory is tree B
.\.venv\Scripts\python.exe manage.py runserver 127.0.0.1:8002
```
Verify each address serves the intended checkout with a project-specific route or visible branch-specific check, and recheck the process's settings if startup loads a different configuration. If a port is occupied, choose another free loopback port and record the one actually used. [Django permits concurrent development servers on separate ports](https://docs.djangoproject.com/en/5.2/ref/django-admin/#runserver); `runserver` is a development tool.
In two further interactive terminals, set the current directory to A and B respectively and start the installed Claude Code CLI with `claude`. Confirm each session's visible working directory and effective permissions before assigning a ticket. Its worktree files have their own branch, while [plugins and repository state may be shared](https://code.claude.com/docs/en/worktrees#what-worktrees-share-with-the-main-checkout). Review project instructions, tools, hooks, MCP connections and any extra directory access. Use ordinary [permission prompts](https://code.claude.com/docs/en/permissions), with a person approving edits and commands under the project's policy; do not enable permission bypass to make two sessions unattended.
Give session A only ticket A's real defect or requested behavior, allowed files, expected output and acceptance checks. Give B its separate ticket. Ask each session to show its plan and changed-file list, stay in its own tree, run only approved local checks, and report failed commands and unfinished work. Keep shared settings or migration files under explicit ownership. Two sessions may still collide logically in models, URLs or data contracts even when their first files differ. Watch their activity and stop a session that reaches for the other tree or a shared service.
## 4. Review each branch before integration
After each session ends or reaches an explicit stop, inspect the corresponding checkout yourself. Record its branch head and status, review the full diff, and run the ticket's actual tests and acceptance check at its own local address. Check for unexpected files, dependency changes, secrets, generated media, model changes and migrations. Use the same scrutiny for code outside the initial file allocation. A session's claim that a test passed is a lead to verify against its command output and your own readback.
If either ticket remains unresolved, retain its branch and local state. Repair the specific failure and rerun affected checks before considering it for integration. Preserve reviewed changes in commits on their respective branches under the owner's normal Git practice. Record commit IDs, effective SQLite paths, ports, checks and observed Claude usage. Anthropic's [`/usage` guidance](https://code.claude.com/docs/en/costs) describes account and session displays; use `unknown` where the account does not expose a figure. Concurrent sessions can use allowance or incur provider charges under the actual plan and limits. There is no assumed speedup or free second session.
## 5. Integrate one branch at a time on a third checkout
Create a clean integration worktree from the approved base commit after the branch reviews. The integration branch is where both changes are evaluated; it is not automatically the protected or shared branch.
```powershell
git worktree add -b <integration-branch> <absolute-integration-path> <approved-base-commit>
```
Repeat step 2 **in that third checkout**: create its own `.venv`, install the repository's pinned dependencies, set its local-only configuration and check the effective SQLite engine and file path before any write. Confirm that this path is inside the integration checkout and differs from A and B. Run the repository's required baseline checks there before merging either branch; record failures. Do not reuse either ticket tree's virtual environment or database. Then integrate A:
```powershell
git -C <absolute-integration-path> merge --no-ff <ticket-a-branch>
```
Inspect A's integrated diff and run the project's required checks. Then merge B into that integration checkout:
```powershell
git -C <absolute-integration-path> merge --no-ff <ticket-b-branch>
```
If Git reports a conflict, retain both ticket branches. Read the competing changes and resolve their intended behavior with the human reviewer; a wholesale choice of one side is not a review. Review the migration graph and schema operations when both branches change models or migrations in the same Django app. Django documents [`makemigrations --merge`](https://docs.djangoproject.com/en/5.2/ref/django-admin/#makemigrations) for migration conflicts, but its generated merge migration still needs human review. Do not run it blindly or reset a database to make a graph error disappear.
With the combined code and a fresh, empty **integration-only** SQLite file, verify the effective path again. Inspect `migrate --plan`, apply the approved migrations, run `makemigrations --check`, `check`, the project's full required suite and **both** ticket acceptance checks. Review the resulting migration state and any data migration behavior. [Django migrations](https://docs.djangoproject.com/en/5.2/topics/migrations/) belong to the code history while their application is database-specific. Separate branch migrations can each pass locally yet conflict after merge.
Record the integrated commit and all real command results. The owner decides whether that exact result can land on a protected or shared branch. A deployment or production database migration needs its own authority and process.
## 6. Preserve local work before cleanup
Stop both development servers and both Claude sessions. For **each** worktree, including integration, inspect tracked changes, untracked files and ignored material. `git status` alone can look clean while an ignored SQLite file, `.env`, virtual environment or media output still matters. Use the repository's own data inventory as well as:
```powershell
git -C <absolute-path-a> status --short --untracked-files=all
git -C <absolute-path-a> ls-files --others --ignored --exclude-standard
git worktree list
```
Repeat for B and integration. Those commands list paths; review the actual contents and ownership privately before removal, without publishing secrets. Confirm the accepted branch commits remain reachable. Preserve any needed ignored data through the owner's approved private backup route. If an uncommitted change, local data or unresolved conflict still matters, **retain that worktree**. Git's ordinary `worktree remove` requires a clean tree, but clean status is not proof that ignored contents are expendable.
Only after that inventory and preservation, remove each eligible linked checkout with `git worktree remove <absolute-path>` and confirm it is absent from `git worktree list`. Do not use `--force` to hide remaining work. Branch deletion is a separate decision. Keep the final record of both ticket commits, integrated commit or hold reason, path and port identities, migration and test readbacks, usage visibility, preserved local data and owner decision.
## Sources & further reading
- [Claude Code: Run parallel sessions with worktrees](https://code.claude.com/docs/en/worktrees) explains session and worktree behavior, shared configuration and cleanup. This guide adds the Django runtime checks that Git cannot provide.
- [Claude Code: Configure permissions](https://code.claude.com/docs/en/permissions) describes interactive command and edit approval and the scope of working-directory access.
- [Claude Code: Manage costs effectively](https://code.claude.com/docs/en/costs) explains `/usage`, plan differences and the limits of local cost estimates.
- [Git: worktree](https://git-scm.com/docs/git-worktree) and [Git: merge](https://git-scm.com/docs/git-merge) document branch checkouts, removal and conflict handling.
- [Django 5.2: settings](https://docs.djangoproject.com/en/5.2/ref/settings/#name), [management commands](https://docs.djangoproject.com/en/5.2/ref/django-admin/), [migrations](https://docs.djangoproject.com/en/5.2/topics/migrations/) and [testing](https://docs.djangoproject.com/en/5.2/topics/testing/overview/) support the database, command and test steps. Check the installed version against the app's pin.
## Sources
- [Anthropic: Run parallel sessions with worktrees](https://code.claude.com/docs/en/worktrees) — Documents parallel sessions, shared repository and Claude project state, fresh worktree setup and cleanup; does not prove Django runtime isolation.
- [Anthropic: Configure permissions](https://code.claude.com/docs/en/permissions) — Documents interactive edit and command approvals, working directories and tool permissions; reader authority and service isolation remain project decisions.
- [Anthropic: Manage costs effectively](https://code.claude.com/docs/en/costs) — Documents usage displays and plan/provider limits; no account bill, concurrency entitlement or speedup was measured here.
- [Git: git-worktree](https://git-scm.com/docs/git-worktree) — Documents linked worktree creation, listing, clean removal and shared metadata; ignored local data requires separate human inventory.
- [Git: git-merge](https://git-scm.com/docs/git-merge) — Documents branch integration and conflicts; does not verify application or migration behavior.
- [Django 5.2: How to install Django](https://docs.djangoproject.com/en/5.2/topics/install/) — Explains local SQLite setup; actual application dependency pin and settings must be inspected.
- [Django 5.2: Settings, database NAME](https://docs.djangoproject.com/en/5.2/ref/settings/#name) — Explains SQLite filename/path setting; guide requires each effective resolved path to be checked.
- [Django 5.2: django-admin and manage.py](https://docs.djangoproject.com/en/5.2/ref/django-admin/) — Documents migrate plan, check, test, runserver and makemigrations flags used in the conditional recipe.
- [Django 5.2: Migrations](https://docs.djangoproject.com/en/5.2/topics/migrations/) — Explains migration files, graph and schema application; combined migrations need fresh database and human review.
- [Django 5.2: Writing and running tests](https://docs.djangoproject.com/en/5.2/topics/testing/overview/) — Describes Django test runner and test database behavior; branch results do not establish merged behavior.
The BIG CHANGE newsletter
The big picture. At your pace.
Recent stories on AI and robotics, the shifts worth watching and practical ideas to use. Choose a daily briefing, weekly digest or monthly perspective.
Next scheduled send (UTC): . Your first edition arrives at the next scheduled send after you confirm.
Your privacy, your choice.
Necessary storage supports site security and remembers your choices. Optional Google Analytics stays off until you allow it. You can read every story with necessary storage only. Privacy details