Claude Code Worktree Database Isolation Guide
Claude Code worktree database isolation means giving every agent its own runtime namespace as well as its own checkout. Git worktrees and Claude Code's --worktree flow separate files and branches, but your app can still point every agent at the same database, port, queue, cache, Docker project, and .env assumptions. If two agents run migrations or tests against the same local database, file isolation will not save you.
What worktrees actually isolate
A Git worktree lets one repository have multiple working directories, so different branches can be checked out at the same time. Claude Code builds on that with native worktree support: you can start a session with claude --worktree feature-auth, and Claude creates a separate directory under .claude/worktrees/ by default.
That solves a real problem. Multiple agents should not edit the same checkout while chasing unrelated tasks. Worktrees give each session its own files and branch while sharing repository history and remotes. Anthropic's own wording is important here: worktrees isolate file edits.
File edits are only one layer of a development environment. Your app process still reads environment variables, opens sockets, connects to databases, writes cache keys, runs migrations, starts workers, and uses local service containers. Those resources do not become isolated because the source tree moved to another directory.
Where agents still collide
The first collision is usually the database. A Rails, Phoenix, Django, or similar app often has one development database and one test database in local config. Two agents can run test suites at the same time and write to the same tables. Worse, branch A may run a migration that branch B's code cannot understand yet.
The second collision is ports. Every web app wants localhost:3000, 4000, or 8000. The first agent starts cleanly. The second hits an address-in-use error, silently switches behavior, or convinces itself the app is already running when it is looking at the wrong branch.
The third collision is environment and dependency state. Fresh worktrees often do not contain gitignored files such as .env, .env.local, .venv, node_modules, vendor/bundle, or generated config. Claude Code has .worktreeinclude for copying selected gitignored files into new Claude-created worktrees, but that only handles files you list and that are actually gitignored.
Docker is similar. Compose project names are the namespace for containers, volumes, and networks. If every worktree runs the same default project name, agents can share service containers and volumes even when their application code differs. That may be acceptable for a simple Redis instance. It is risky for databases, search indexes, object stores, and anything migrations mutate.
A practical Claude Code worktree database isolation pattern
Use a deterministic worktree ID and apply it everywhere runtime state can collide. The ID can come from the worktree directory name, branch slug, or a wrapper script. Keep it short, shell-safe, and stable for the life of the worktree.
For databases, create a per-worktree name such as myapp_dev_feature_auth and myapp_test_feature_auth. This mirrors the idea used by parallel test runners: each worker gets its own database, with a suffix that keeps schema and data separate. For PostgreSQL, direct database creation is normal, but template-based cloning has connection caveats, so setup scripts should be explicit and idempotent.
For ports, reserve a port block per worktree. One common pattern is to hash the worktree ID into a range and write the result into generated local config. The important part is that the agent can discover the assigned ports without guessing. Put them in .env.worktree, framework config, a launch file, or Claude context that is generated by the same setup step.
For Docker Compose, set COMPOSE_PROJECT_NAME or pass -p using the same worktree ID. You can still share heavyweight base images and dependency caches, but containers, volumes, and networks need namespacing when branch-specific state matters.
For secrets and env files, choose deliberately. Copying .env into each worktree reduces accidental mutation of the main file. Generating .env.worktree from a template is cleaner when ports and database names must vary. direnv is useful because it loads and unloads environment variables by directory, but shared paths inside .envrc still need review.
Be careful with symlinks. Symlinking a shared read-only cache can save time. Symlinking a mutable .venv or dependency directory can make one agent's package install change another agent's run. Treat mutable dependencies as either per-worktree or managed by a tool that understands concurrency.
Where Claude Code hooks fit
Claude Code gives you several places to wire this in. .worktreeinclude is the lightest option when all you need is copied gitignored files. A SessionStart hook can detect that Claude is running inside a worktree, copy or generate env files, run direnv allow, and call a bootstrap script before useful work starts.
WorktreeCreate and WorktreeRemove are more powerful, but there is a sharp edge. The documented behavior says WorktreeCreate replaces Claude Code's default git behavior. That means if you use it as a setup hook, you may also need to reproduce worktree creation details that Claude would otherwise handle. Teams have asked for a post-create setup hook because environment initialization and VCS creation are different jobs.
In practice, many teams still use hooks because deterministic setup beats hoping an agent reads CLAUDE.md and remembers every manual step. A 2026 GitHub-reviewed Claude Code advisory also tied worktree trust and hook handling to arbitrary-code risk, so treat hook scripts as security-sensitive. If you do, keep scripts small, idempotent, and version-aware. Hooks run with the user's permissions, so quote shell variables, validate paths, block path traversal, and avoid writing secrets into logs or broad shared locations.
Platform checklist
Use this as the minimum bar before you let several Claude Code agents work on the same app in parallel:
- Name: create one stable worktree ID and reuse it for databases, ports, Compose projects, generated env files, and cleanup labels.
- Provision: create per-worktree dev and test databases, load schema, run migrations, and generate local config before the agent runs tests.
- Namespace: assign ports, Compose project names, volumes, queues, cache prefixes, search indexes, and object-store buckets per worktree when state can diverge.
- Hydrate: copy or generate required gitignored files with
.worktreeinclude,direnv, or a bootstrap script. Do not assume fresh worktrees contain secrets or dependency directories. - Tell the agent: write the active database names, ports, and commands somewhere Claude can read, such as generated context or a launch config.
- Verify: run a cheap smoke test that prints the database URL, app port, Compose project, and current worktree path before longer tests begin.
- Teardown: pair creation with
WorktreeRemove,DROP DATABASE,docker compose down -v, and a garbage collector for orphaned resources.
The rule is simple: treat each agent worktree like a small environment, not a folder. Share repository history and the state that should be central, such as task metadata if your workflow needs it. Isolate anything that migrations, tests, servers, workers, or package managers can mutate. That is the difference between parallel Claude Code sessions that increase throughput and parallel sessions that create invisible local failures.