Git Worktree and node_modules
One of the most frequently asked questions about git worktree in JavaScript and TypeScript projects: do you need to run npm install in every worktree? The short answer is yes. Here is why, and what you can do about it.
Do You Need npm install in Each Worktree?
Yes. Each worktree has its own working directory, and node_modules is part of the working directory. When you run git worktree add, Git checks out the files tracked by Git — but node_modules is in .gitignore, so it is never checked out. You get an empty worktree with no dependencies installed.
# Create a new worktree
git worktree add ../myapp-feature feature/auth
# Enter the worktree
cd ../myapp-feature
# Try to run the project — this will fail
npm start
# Error: Cannot find module 'react'
# You must install dependencies first
npm install # or: yarn install / pnpm installWhy node_modules Is Not Shared
Worktrees share the Git object database (commits, blobs, trees) and refs (branches, tags). They do not share untracked or ignored files. Since node_modules is in .gitignore, it is invisible to Git and therefore per-worktree.
This is actually a good thing. Different branches may have different dependencies in their package.json and package-lock.json. Sharing node_modules across branches would cause version conflicts and subtle bugs.
The same applies to other ignored artifacts: build output (dist/, build/), virtual environments (.venv/), and compiled binaries. Each worktree needs its own copy.
Strategies for Managing node_modules
1. Use pnpm and its global store
pnpm uses a content-addressable store that deduplicates packages globally. Each worktree still gets its own node_modules, but packages are hard-linked from a shared store, so disk usage is dramatically lower and installs are faster.
# Install pnpm if you haven't
npm install -g pnpm
# In each worktree, run:
pnpm install
# pnpm stores packages in ~/.local/share/pnpm/store
# Each worktree's node_modules uses hard links to that store
# 5 worktrees ≈ same disk usage as 1 with npm2. Script it with npm ci
Use npm ci instead of npm install for faster, deterministic installs. It skips the dependency resolution step by using the lockfile directly.
# npm ci is faster than npm install for clean installs
# It deletes node_modules first and installs from package-lock.json
cd ../myapp-feature
npm ci3. Symlinks (with caveats)
You can symlink node_modules from one worktree to another, but this is risky. It only works if both branches have identical dependencies. If they diverge, one worktree will have wrong versions, leading to hard-to-debug issues.
# Symlink node_modules (ONLY if branches have same dependencies)
cd ../myapp-feature
ln -s ../myapp/node_modules node_modules
# WARNING: If feature/auth changes package.json, this will break.
# The symlinked node_modules won't match the lockfile.
# Use pnpm instead for safe deduplication.Handling .env Files
Like node_modules, .env files are typically in .gitignore and therefore not shared between worktrees. Each worktree needs its own .env file.
# After creating a worktree, copy your .env file
cd ../myapp-feature
cp ../myapp/.env .env
# Or keep a .env.example in the repo (tracked by Git)
# and copy it in each worktree
cp .env.example .envFor a deeper dive into environment file management, see the .gitignore and .env files guide.
Shell Helper Script
Automate worktree creation with dependency installation by adding a helper function to your shell configuration.
# Add to ~/.bashrc or ~/.zshrc
# Create worktree + install deps + copy .env
gwt() {
local dir="$1"
shift
git worktree add "$dir" "$@" || return 1
cd "$dir" || return 1
# Install dependencies based on lockfile type
if [ -f "pnpm-lock.yaml" ]; then
echo "Installing with pnpm..."
pnpm install
elif [ -f "yarn.lock" ]; then
echo "Installing with yarn..."
yarn install
elif [ -f "package-lock.json" ]; then
echo "Installing with npm ci..."
npm ci
fi
# Copy .env if it exists in the parent worktree
local main_dir
main_dir="$(git worktree list --porcelain | head -1 | cut -d' ' -f2)"
if [ -f "$main_dir/.env" ] && [ ! -f ".env" ]; then
cp "$main_dir/.env" .env
echo "Copied .env from main worktree"
fi
}
# Usage:
# gwt ../myapp-feature feature/auth
# gwt ../myapp-hotfix -b hotfix/urgentThis function handles dependency installation for npm, yarn, and pnpm projects automatically, and copies your .env file from the main worktree.