Git Worktrees or One VM per Agent for Parallel Coding Agents?
Updated October 27, 2026 .md
Short answer: Use git worktrees when parallel agents only edit and test code. They separate files but share one machine's ports, hooks, home directory, credentials and services. When agents run dev servers, databases or Docker, give each one its own VM, so every agent can bind port 3000 and gets its own URL.
This page is the decision. For the step-by-step setup of one VM per agent, see Run several coding agents in parallel.
What a worktree separates, and what it shares#
A git worktree is a second working directory attached to the same repository. Git's docs list what is per-worktree and what is shared:
| Thing | Per worktree | Shared by all worktrees |
|---|---|---|
Checked-out files, index, HEAD |
Yes | |
Branches and other refs under refs/ |
Yes, and one branch can be checked out in only one worktree | |
| Object store (commits, blobs) | Yes, in the main repository's .git |
|
Repository config (.git/config) |
Only if you enable extensions.worktreeConfig |
Yes by default |
Hooks (.git/hooks) |
Yes, they live in the common directory | |
~/.gitconfig, ~/.bashrc, ~/.ssh, cloud credentials |
Yes: same user, same home | |
Package caches such as npm's (~/.npm by default) |
Yes | |
node_modules and other untracked files |
Yes, so each worktree installs its own | |
| Ports, Docker daemon, local databases, CPU and RAM | Yes: it's one machine |
Git isolates the source tree. Everything outside the source tree is still one machine.
The collision, reproduced#
We ran this on a real small sandbox ($A below is its id): one repository, two worktrees, one per agent, and a tiny Node server whose npm run dev listens on port 3000 and replies with its working directory.
git worktree add -b agent-a ../wt-a
git worktree add -b agent-b ../wt-b
git worktree list/home/user/app 514dba2 [main]
/home/user/wt-a 514dba2 [agent-a]
/home/user/wt-b 514dba2 [agent-b]Agent A starts its dev server in the background. Then agent B starts the same one in its own worktree:
sbx exec $A --cwd wt-a --detach "npm run dev > ~/wt-a.log 2>&1" # log: listening on 3000
sbx exec $A --cwd wt-b "npm run dev"Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (node:net:1941:16)
…
at Object.<anonymous> (/home/user/wt-b/server.js:4:4)
code: 'EADDRINUSE',The quieter failure is worse. Agent B's tests hit agent A's server and pass or fail for code agent B never wrote:
cd ~/wt-b && curl -s localhost:3000hello from /home/user/wt-aThen we checked the rest of the shared state from both worktrees:
for w in ~/wt-a ~/wt-b; do (cd $w && git config user.email && git rev-parse --path-format=absolute --git-path hooks); doneagents@example.com
/home/user/app/.git/hooks
agents@example.com
/home/user/app/.git/hooksBoth agents commit as the same identity and run the same hooks. When agent A wrote a pre-commit hook from its worktree, agent B's next commit in wt-b failed with exit 1 and printed pre-commit hook from agent A: blocking. Agent B couldn't check out agent A's branch either:
fatal: 'agent-a' is already used by worktree at '/home/user/wt-a'Finally, a token agent A added to ~/.bashrc showed up in agent B's shell:
wt-b sees GITHUB_TOKEN=ghp_agentA_exampleYou can work around the port by giving each worktree its own PORT. You then also need separate database names, Docker Compose project names, cache directories and credentials, and you have to tell every agent which ones are its own.
The same thing, one VM per agent#
We then gave agent B a second sandbox ($B) with the same project files on branch agent-b, and left agent A's server running in the first. Each VM binds port 3000 without asking the other, and sbx host gives each one its own HTTPS URL:
sbx exec $B --cwd app --detach "npm run dev > ~/dev.log 2>&1" # log: listening on 3000
sbx host $A 3000 --public
sbx host $B 3000 --public{"ok":true,"type":"port.hosted","sandboxId":"sb_9aqguz0uq7","port":3000,"url":"https://mossy-merry-yak-3000.box.sandboxer.com","access":"public",…}
{"ok":true,"type":"port.hosted","sandboxId":"sb_f3d9nvqlt0","port":3000,"url":"https://arctic-broad-cape-3000.box.sandboxer.com","access":"public",…}curl -s https://mossy-merry-yak-3000.box.sandboxer.com
curl -s https://arctic-broad-cape-3000.box.sandboxer.comhello from /home/user/wt-a
hello from /home/user/appIn the second VM, git config user.email returned agent-b@example.com, and GITHUB_TOKEN was unset: agent A's ~/.bashrc edit stayed in agent A's VM. Leave out --public to get private URLs that carry a token instead (see Hosting).
Decision table#
| Your agents… | Worktrees on one machine | One VM per agent |
|---|---|---|
| Only edit code and run unit tests | Works well; free and instant | Works; costs machine time |
| Each run a dev server or preview | Port per worktree, managed by hand | Every agent uses its usual port; one URL each |
| Need a database or Docker Compose stack | Shared daemon; rename every project, volume and database | Own Docker and own database per agent |
| Install hooks, global tools or dotfiles | Changes reach every worktree | Stay in that VM |
| Should hold different credentials | Hard: same user and home directory | Pass different variables per sandbox with -e |
| Run for hours | Your machine has to stay awake | Keeps running while your laptop sleeps |
| Need many at once | Limited by one machine's CPU and RAM | 100 at once on the $20 plan (2 during the trial) |
| Need to share the object store to save disk | Yes, one .git |
Each VM has its own clone |
| Must work offline | Yes | No |
A middle ground: run the worktrees inside one sandbox when the tasks share an environment, and give a VM to each task that needs its own ports or services.
What one VM per agent costs#
Sandboxes are billed per second while they run, and stopped sandboxes cost nothing. Per agent-hour:
| Size | vCPU / RAM | Per agent-hour | 5 agents for 3 hours |
|---|---|---|---|
small |
2 / 4 GB | $0.018 | $0.27 |
default |
4 / 8 GB | $0.036 | $0.54 |
large |
8 / 16 GB | $0.072 | $1.08 |
These are machine prices only. Model tokens are billed separately by your model provider on your own key. To avoid setting up each VM by hand, prepare one sandbox, save it as a named snapshot and start each agent from it (Turn a sandbox into a reusable template).
FAQ#
Can't I just give each worktree a different port?#
Yes, and for one dev server per agent that's enough. It doesn't separate the shared hooks, ~/.gitconfig, credentials, Docker daemon or databases, and every agent has to be told which port is its own.
Do worktrees save disk compared with one clone per VM?#
Yes. Worktrees share one object store, so a second worktree adds only the checked-out files and its own node_modules. Each VM holds its own clone, but you pay for running time, not for the clone.
How do agents in separate VMs share their work?#
Through git, the same as a team: each agent commits on its own branch and pushes. You review the branches and merge the good ones.
Can I still use worktrees inside a sandbox?#
Yes. A sandbox is an ordinary Ubuntu VM, and everything on this page ran inside one. Use worktrees there when the tasks can share that VM's ports and services.
Related#
More guides
For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.
For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.
The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.
If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.