Originally published at hafiz.dev
You're deep into a Claude Code session. You've been going back and forth with it for twenty minutes. It knows your service layer, it knows why that repository is structured the way it is, it's finally building the feature the way you want it built. Three files are open and mid-edit. Then your phone buzzes. Your own site has a bug in production.
So what do you do?
If you stash your changes and switch branches, you lose Claude's context. Start a new session on the main branch and you're explaining the codebase all over again from scratch. If you open a second terminal and try to work on the same files from a different branch, you're asking for trouble. Uncommitted changes collide. Migrations step on each other. Your Herd site serves the wrong branch. And if you're running queue workers or a Vite dev server, good luck keeping track of which process belongs to which branch.
This situation comes up constantly once you're using Claude Code as your daily driver. A client feature, your own project needing attention, a hotfix, an experiment you want to run without touching production-ready code. The shared-working-directory model doesn't scale when you're actually parallelising work.
This is the problem git worktrees solve. And now that Claude Code has native worktree support built in, there's genuinely no excuse not to be using this workflow. Let me show you how to set it up properly for a Laravel project, because the generic tutorials skip all the Laravel-specific parts.
What a Git Worktree Actually Is
Most developers have used git for years without ever touching worktrees. The mental model is simple once you see it.
Normally, your git repository has one working directory. Every branch you check out lives in the same set of files on disk. Switch branches and your files change. That's just how git works.
A worktree is a second (or third, or fourth) working directory attached to the same repository. Each worktree has its own branch and its own independent files on disk. But they all share the same git history, the same objects, the same remotes. You commit in one worktree, that commit is available in every other worktree immediately.
# Your main project
/projects/my-app/ ← main branch, your primary Claude session
# A linked worktree
/projects/my-app/.claude/worktrees/feature-billing/ ← feature/billing branch, second Claude session
Both directories are the same codebase. Different branches. Completely independent files. You can run both at the same time without them knowing the other exists.
It's not a new feature. Git has had worktrees since 2015. What changed is that Claude Code now supports them natively, which makes spinning up an isolated AI session a one-command operation.
Why This Matters for Claude Code Specifically
Here's what most people miss: switching branches mid-session doesn't just break your files. It breaks your AI's context too.
Claude Code builds up an understanding of your codebase over the course of a session. It reads your files, asks clarifying questions, figures out your patterns. That context lives in the conversation. When you stash your changes, switch branches, and start a new task, that built-up knowledge is gone. You're starting from scratch again.
Worktrees solve this at the filesystem level. Each session stays in its own directory, on its own branch. Claude isn't confused about which files belong to which task. It doesn't try to read a migration that only exists in a different branch. It doesn't see half-written code from a feature that hasn't landed yet. Everything it sees belongs to the session it's running.
Think about what that means for a complex Laravel app. Service providers, event listeners, Eloquent relationships, custom artisan commands. Claude Code builds a map of all of this. That map is specific to the codebase state it's looking at. Give it a clean, isolated environment and the map stays accurate.
This connects directly to the idea of making your app genuinely AI-agent friendly. The cleaner the environment an agent operates in, the less time it spends correcting for confusion. A worktree is a clean environment by default.
The Laravel-Specific Problem
A raw git worktree add gives you the files. That's it. For a vanilla JavaScript project, that might be enough.
For a Laravel project, you need a lot more:
- A separate database (so migrations in branch A don't break branch B)
- A separate
.envfile with the rightAPP_URL,DB_DATABASE, andSESSION_DOMAIN - A separate Herd site so you can open both branches in a browser at the same time
- A Vite dev server on a different port so the two don't conflict
None of the generic git worktree tutorials cover this. Let me walk through each piece.
Setting Up a Laravel Worktree the Right Way
Step 1: Create the worktree
From your project root:
git worktree add .claude/worktrees/feature-billing -b feature/billing
This creates a new directory at .claude/worktrees/feature-billing/ checked out on a new branch called feature/billing. Add .claude/worktrees/ to your .gitignore right now so git doesn't try to track these directories.
echo ".claude/worktrees/" >> .gitignore
Step 2: Create a dedicated database
This is the step people skip and then wonder why their migrations are broken.
mysql -u root -e "CREATE DATABASE myapp_billing;"
Each worktree needs its own database. Shared databases cause real problems. One branch has a migration that adds a column. The other branch doesn't know about it. Your tests start failing in ways that have nothing to do with your code. Don't share databases between worktrees.
Step 3: Configure the worktree's .env
Navigate into the worktree directory and copy your main .env:
cd .claude/worktrees/feature-billing
cp ../../.env .env
Then update three things in the new .env:
APP_URL=http://myapp-billing.test
DB_DATABASE=myapp_billing
SESSION_DOMAIN=myapp-billing.test
If you're using Sanctum, also update SANCTUM_STATEFUL_DOMAINS to match the new domain.
Step 4: Register the worktree with Laravel Herd
From inside the worktree directory:
herd link myapp-billing
This registers the directory as a Herd site at http://myapp-billing.test. You can now open both your main branch and your feature branch in a browser side by side. They're completely independent.
Step 5: Run migrations and install dependencies
php artisan migrate
composer install
npm install
You need separate vendor/ and node_modules/ directories per worktree. They don't share dependencies.
Step 6: Start Vite on a different port
Update vite.config.js in the worktree to use a different dev server port, or just pass the port at runtime:
npm run dev -- --port 5174
Your main project is probably already running on 5173. Pick anything different. This prevents the two Vite instances from conflicting.
Step 7: Start Claude
claude
You now have a fully isolated Laravel environment. Its own branch, its own database, its own Herd domain, its own Vite server, its own Claude session.
The Faster Way: Native Claude Code Worktree Support
Claude Code v2.1.49 (released February 19, 2026) added native worktree support via the --worktree flag. You can skip the manual git worktree add step entirely:
# From your project root
claude --worktree feature-billing
This creates the worktree at .claude/worktrees/feature-billing/, checks out a new branch called worktree-feature-billing, and opens a Claude session scoped to that directory. All in one command.
There's also a shorthand:
claude -w feature-billing
And if you want tmux integration for side-by-side terminal panes:
claude --worktree feature-billing --tmux
The --tmux flag gives you a Claude pane and a shell pane in the same terminal window. Useful for running artisan commands alongside your Claude session.
One important note: the native flag handles the git setup automatically, but it doesn't know about your Laravel environment. You still need to manually create the database, update .env, and run migrations before the Laravel app will actually work. The git isolation is automatic. The Laravel isolation is your job.
When you exit a session started with --worktree, Claude prompts you to keep or remove the worktree. If you made no changes, it cleans up automatically. If you have commits, it asks. That cleanup behaviour is genuinely nice. You don't end up with a graveyard of stale worktrees.
Worktree Naming Conventions That Actually Help
Nobody talks about this, but the name you give a worktree matters more than it seems. You're going to have multiple terminals open. You're going to be switching between them. A bad naming scheme means you're constantly checking which terminal is which.
A few conventions that work well in practice:
Use a prefix that tells you the type of work. feature-, hotfix-, experiment-, refactor- at the start tells you immediately what kind of session it is without reading the rest of the name.
claude -w feature-stripe-webhooks
claude -w hotfix-login-redirect
claude -w experiment-redis-cache
Keep names short but specific. feature-billing is fine. feature-billing-invoice-pdf-generation-fix is not. You'll be typing or tab-completing this constantly. Two or three words after the prefix is enough.
Match the worktree name to the branch name you'll eventually open a PR for. When Claude creates the worktree with --worktree feature-billing, it names the branch worktree-feature-billing. If you're creating worktrees manually with git worktree add, use the same name as the intended PR branch so the diff you review at the end maps cleanly to what you planned.
For experiments, be explicit. If you're not sure the work will ship, name it experiment- rather than feature-. It sets the right expectation for yourself when you come back to it two days later and decide whether to keep or discard. When you eventually paste the diff into the diff checker to review what actually changed, a well-named worktree reminds you what you were trying to prove.
Small thing. But when you're managing three parallel sessions it genuinely reduces friction.
When Worktrees Are Overkill
I want to be honest about this because not every situation needs worktrees.
If you're a solo developer working on a single project with no parallel tasks, you don't need this. The overhead of setting up a second database and Herd site is real, and if you're not actually running parallel sessions it's just friction with no payoff.
Quick bug fixes don't need worktrees either. If something takes five minutes to fix and you can stash your current work without losing meaningful context, stash it. Worktrees are for situations where you're running two genuinely parallel threads of work.
There's also a legitimate concern about context window management. Running three Claude Code sessions simultaneously means burning tokens across three conversations. If you're on a limited plan, be deliberate about which sessions are actually active versus just parked.
The pattern I described in Stop Vibe Coding Your Production Apps applies here too: worktrees aren't a reason to let AI run unsupervised on multiple features at once. You're still the one reviewing and directing. Parallelism helps with context switching. It doesn't replace judgment.
If you want to go deeper on what makes a Claude Code workflow actually productive, the Laravel Skills Directory covers reusable agent skills that work well alongside the worktree setup, particularly for repetitive tasks like creating tools or running migrations across branches.
FAQ
Does each worktree need its own vendor/ and node_modules/ directories?
Yes. Worktrees don't share dependencies. When you create a new worktree, you need to run composer install and npm install in it before the Laravel app will work. This adds setup time but prevents version conflicts between branches.
Can I use the same Redis instance across worktrees?
It depends what you're using Redis for. Queue workers and cache are generally fine to share as long as you're using different prefixes. Sessions are trickier. If both worktrees are running simultaneously and sharing a session store, you'll get interference. The safest approach is to configure a unique REDIS_PREFIX per worktree in your .env.
What happens to my worktrees if I delete the main project directory?
Worktrees are linked to the main repository. If you delete the main .git directory or the main project, the worktrees become orphaned and won't work properly. Always clean up worktrees before removing a project: git worktree list to see what's active, then git worktree remove for each one.
Do I need to set up the whole CLAUDE.md file again in each worktree?
No. The CLAUDE.md file lives in your repository and is checked out with your code in each worktree. If you have project-specific instructions in CLAUDE.md, they'll be available in every worktree automatically. This is one of the reasons keeping your CLAUDE.md well-maintained pays off. The investment applies across every session and every worktree.
Can I run feature branch A and feature branch B against the same staging database for integration testing?
You can, but I'd advise against it for active development. The value of worktrees is isolation. Sharing a database reintroduces the exact dependency problems you're trying to avoid. Use separate databases during development and only test against shared infrastructure in a proper staging environment.
Git worktrees aren't a new trick. They've been in git for years and most developers have never needed them. But Claude Code changes the calculus. When your AI agent needs a stable, consistent filesystem to build real context about your codebase, giving it a dedicated environment isn't a luxury. It's just good practice.
The Laravel-specific setup takes maybe ten minutes the first time. After that it's fast. And once you've run two parallel sessions without a single stash or merge conflict, you won't go back.
If you're building AI-powered features and want to talk through the architecture, get in touch.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.