REACT NATIVE

How I Work On 5 Features At A
Time In React Native Using Git Worktrees

Yagyesh Bobde29 Mar 20263 min read
How I Work On 5 Features At A Time In React Native Using Git Worktrees

So here's a problem I kept running into.

I'm building two features minimum at the same time. One needs testing on Device A, the other on Device B. But every time I switched branches, I had to kill Metro, rebuild, reinstall, wait — and by the time everything was back up, I'd already lost the context I was working in.

There had to be a better way.

Turns out, there is. It's called Git Worktrees — and it's probably the most underrated tool to boost productivity especially with AI.

What Even Is a Git Worktree?

Think of it like running two copies of your project — each on a different branch — at the same time. No switching. No stashing. No "wait let me rebuild."

Git Worktrees let you check out a branch into a completely separate folder. Each folder has its own Metro, its own build, its own life.

terminalbash
git worktree add ../app-feature-a feat/feature-a
git worktree add ../app-feature-b feat/feature-b

That's it. Two branches. Two folders. Two devices. Zero context-switching.

The Traps Nobody Warns You About

This sounds clean in theory. In practice, Android development throws three specific wrenches at you.

Trap 1: Don't nest worktrees inside your project.

If you create your worktree inside the project root — like project/.worktrees/feature-a — Metro's file watcher picks up both trees. It gets confused, causes cache collisions, sometimes serves the wrong bundle entirely.

Keep them as siblings:

directory structuretext
~/Developer/
  my-app/           ← main branch
  my-app-feature-a/ ← worktree A
  my-app-feature-b/ ← worktree B

Trap 2: --deviceId doesn't actually isolate Gradle.

Running:

terminalbash
npx react-native run-android --deviceId DEVICE_A --port 8081

looks like it targets one device. But Gradle's installDebug ignores --deviceId entirely — and happily installs the APK on every connected device. So Device B gets Feature A's build. Fun times.

The fix is ANDROID_SERIAL:

terminalbash
ANDROID_SERIAL=<DEVICE_A_ID> npx react-native run-android --deviceId <DEVICE_A_ID> --port 8081

ANDROID_SERIAL restricts everything — including Gradle — to one device.

Trap 3: adb reverse stomps across devices.

When React Native runs, it executes adb reverse to forward Metro traffic from device → machine. Without specifying which device, it runs against all connected devices — overwriting the port rules you just set up for the other one.

Fix this before each build:

terminalbash
adb -s <DEVICE_A_ID> reverse --remove-all
adb -s <DEVICE_B_ID> reverse --remove-all

adb -s <DEVICE_A_ID> reverse tcp:8081 tcp:8081
adb -s <DEVICE_B_ID> reverse tcp:8082 tcp:8082

And verify after every install run — because a rogue adb reverse can silently redirect a device to the wrong Metro.

The Full Setup That Actually Works

Here's the whole flow, no hidden steps:

1. create worktreesbash
git worktree add ../app-feature-a feat/feature-a
git worktree add ../app-feature-b feat/feature-b
2. copy env filesbash
# .env files are gitignored — copy them manually (if using ai add them in rules)
cp .env ../app-feature-a/.env
cp .env ../app-feature-b/.env
3. install depsbash
# Install deps in each
cd ../app-feature-a && npm install
cd ../app-feature-b && npm install
4. start metro (terminal 1)bash
# Terminal 1
cd ~/Developer/app-feature-a
npx react-native start --port 8081
5. start metro (terminal 2)bash
# Terminal 2
cd ~/Developer/app-feature-b
npx react-native start --port 8082
6. pin devicesbash
adb -s <DEVICE_A_ID> reverse tcp:8081 tcp:8081
adb -s <DEVICE_B_ID> reverse tcp:8082 tcp:8082
7. build feature A → device Abash
# Feature A → Device A
ANDROID_SERIAL=<DEVICE_A_ID> npx react-native run-android --deviceId <DEVICE_A_ID> --port 8081
8. build feature B → device Bbash
# Feature B → Device B
ANDROID_SERIAL=<DEVICE_B_ID> npx react-native run-android --deviceId <DEVICE_B_ID> --port 8082

Why This Matters

Context-switching is silent time theft. Every branch switch, every Metro restart, every "wait for the build" — it adds up. And for Android especially, rebuilds aren't exactly instant.

Once this setup clicked, my parallel development flow actually felt parallel. Two devices live on my desk. Two Metro instances running. Two features being built and tested simultaneously.

It's one of those setups where once you have it, you can't go back.

Written by

Yagyesh Bobde

Software DevelopmentReact NativeAIGit WorktreeMultitasking

Originally published on

Read this article on Medium