> Full Neon documentation index: https://neon.com/docs/llms.txt

# Isolated Subagents: Running Claude Code in parallel with Neon Database Branching

Automate parallel feature development by giving every Claude Code subagent its own Git worktree and isolated database sandbox.

While modern AI assistants generate code at remarkable speeds, the development process often remains sequential. You ask an agent to build a feature and wait. You request a query optimization and wait again. This workflow is bottlenecked by the linear nature of the standard AI interface, which can only run one agent at a time, completing one task before starting the next.

It's tempting to ask: _Why not just open multiple terminals and run several agents in parallel?_

If you've ever tried doing that, you've likely encountered one of these common issues:

1. **Codebase collisions:** Agents try to modify the same files, overwriting each other's work.
2. **Tangled Git states:** Sharing a single local branch leads to locked indexes or messy, overlapping commits.
3. **Database corruption:** Multiple agents running schema migrations, dropping tables, or seeding test data against a single local database results in immediate, chaotic failures.

The root problem is a lack of stateful isolation. For AI agents to work in parallel, every agent needs its own dedicated sandbox not just for files, but for data.

In this guide, you'll learn how to build this workflow using **Claude Code Subagents** with **Neon Database Branching**.

Using Claude Code's worktree isolation with a custom Neon Git hook, you'll build an automated workflow where every subagent is instantly provisioned its own lightweight directory _and_ its own isolated database branch.

**Info: New to Git worktrees?** If you aren't familiar with how Git worktrees function under the hood to isolate file systems, check out [Git worktrees and Neon Branching](https://neon.com/guides/git-worktrees-neon-branching) for a better understanding of how this powerful combination enables safe parallel development.

To demonstrate this in action, a social media application built with Next.js and Drizzle ORM is used as an example throughout the guide. You'll use two Claude subagents to work simultaneously: one building a new **API Key Management** feature, and the other optimizing a slow **User Activity Feed**.

## Prerequisites

Before you begin, ensure you have the following:

- **Claude Code:** Anthropic's official CLI tool installed. Visit [Claude code docs](https://code.claude.com/docs/en/quickstart#step-1-install-claude-code) for installation instructions.
- **Neon account and project:** A Neon account with an active project. Sign up at [neon.new](https://neon.new).
- The [Neon CLI](https://neon.com/docs/reference/neon-cli) installed (`npm i -g neonctl` or `brew install neonctl`).
- **Example application with Git repository**: Any application with a Git repository. This guide uses a Next.js app with Drizzle ORM (a simple social media app) as an example, but you can follow along with your own codebase. The emphasis here is on demonstrating the parallel workflow rather than the specifics of the application.

## Step 1: Set up the Neon Git hook for database branching

Claude Code subagents use [Git worktrees](https://git-scm.com/docs/git-worktree) under the hood when configured for isolation. To make sure each worktree automatically gets its own database branch, you need to set up a Git hook.

Whenever Claude creates a new worktree, this hook will intercept the process, call the Neon API to create a database branch, and inject the new `DATABASE_URL` into the subagent's `.env` file.

Navigate to your project root and create the `post-checkout` hook:

```bash
touch .git/hooks/post-checkout
chmod +x .git/hooks/post-checkout
```

Paste the following script into `.git/hooks/post-checkout`:

```bash
#!/bin/bash
set -euo pipefail

# Git post-checkout hook: syncs Neon database branch with current Git branch
# Args: $1 = previous HEAD, $2 = new HEAD, $3 = checkout type (1=branch, 0=file)
if [ "${3:-0}" != "1" ]; then
  exit 0
fi

GIT_ROOT=$(git rev-parse --show-toplevel)
ENV_FILE="$GIT_ROOT/.env"

IS_WORKTREE_CREATION=0
if [ "${1:-}" = "0000000000000000000000000000000000000000" ]; then
  IS_WORKTREE_CREATION=1
fi

find_seed_env_file() {
  local current_root="$1"
  local line
  local worktree_path

  while IFS= read -r line; do
    case "$line" in
      worktree\ *)
        worktree_path="${line#worktree }"
        if [ "$worktree_path" != "$current_root" ] && [ -f "$worktree_path/.env" ]; then
          printf '%s' "$worktree_path/.env"
          return 0
        fi
        ;;
    esac
  done < <(git worktree list --porcelain)

  if [ -f "$current_root/.env.example" ]; then
    printf '%s' "$current_root/.env.example"
    return 0
  fi

  return 1
}

if [ ! -f "$ENV_FILE" ]; then
  if [ "$IS_WORKTREE_CREATION" = "1" ]; then
    echo "ℹ️  New worktree detected - bootstrapping .env"
  fi

  if SEED_ENV_FILE=$(find_seed_env_file "$GIT_ROOT"); then
    cp "$SEED_ENV_FILE" "$ENV_FILE"
    echo "✅ Created .env from: $SEED_ENV_FILE"
  else
    echo "❌ .env file not found at: $ENV_FILE"
    echo "   Create one (or .env.example) in this worktree, then retry checkout."
    exit 1
  fi
fi

if ! command -v neon &>/dev/null; then
  echo "❌ Neon CLI not found. Install it with: brew install neonctl  OR  npm i -g neonctl"
  exit 1
fi

# Skip detached HEAD (tag/commit checkout)
BRANCH_NAME=$(git symbolic-ref --short HEAD 2>/dev/null) || {
  echo "ℹ️  Detached HEAD - skipping Neon branch sync"
  exit 0
}

echo "🔄 Syncing Neon branch with Git branch: $BRANCH_NAME"

# Parse .env without `source` to handle values with shell metacharacters
get_env_value() {
  local key="$1"
  local value
  value=$(grep -E "^${key}=" "$ENV_FILE" | head -1 | cut -d'=' -f2-) || true
  value="${value#\"}" ; value="${value%\"}"
  value="${value#\'}" ; value="${value%\'}"
  value="${value%$'\r'}"
  printf '%s' "$value"
}

NEON_API_KEY=$(get_env_value "NEON_API_KEY")
NEON_PROJECT_ID=$(get_env_value "NEON_PROJECT_ID")

if [ -z "$NEON_API_KEY" ]; then
  echo "❌ NEON_API_KEY not found in .env file"
  exit 1
fi

if [ -z "$NEON_PROJECT_ID" ]; then
  echo "❌ NEON_PROJECT_ID not found in .env file"
  exit 1
fi

export NEON_API_KEY

# Create Neon branch if it doesn't exist
if neon branches get "$BRANCH_NAME" --project-id "$NEON_PROJECT_ID" >/dev/null 2>&1; then
  echo "✅ Neon branch already exists: $BRANCH_NAME"
else
  echo "🌱 Creating Neon branch: $BRANCH_NAME"
  if ! neon branches create --name "$BRANCH_NAME" --project-id "$NEON_PROJECT_ID" >/dev/null; then
    echo "❌ Failed to create Neon branch: $BRANCH_NAME"
    exit 1
  fi
fi

CONNECTION_URI=$(neon connection-string "$BRANCH_NAME" --pooled --project-id "$NEON_PROJECT_ID" 2>/dev/null) || true
CONNECTION_URI="${CONNECTION_URI#\"}" ; CONNECTION_URI="${CONNECTION_URI%\"}"

if [ -z "$CONNECTION_URI" ]; then
  echo "❌ Failed to retrieve connection string for branch: $BRANCH_NAME"
  exit 1
fi

# Update DATABASE_URL safely
tmp_file="$ENV_FILE.tmp.$$"
trap 'rm -f "$tmp_file"' EXIT

grep -v "^DATABASE_URL=" "$ENV_FILE" > "$tmp_file" || true

if [ -s "$tmp_file" ] && [ "$(tail -c1 "$tmp_file" | wc -l)" -eq 0 ]; then
  echo >> "$tmp_file"
fi

printf 'DATABASE_URL="%s"\n' "$CONNECTION_URI" >> "$tmp_file"
mv "$tmp_file" "$ENV_FILE"

echo "✅ DATABASE_URL updated for branch: $BRANCH_NAME"
```

The above git hook assumes that your application retrieves the database connection string from an environment variable named `DATABASE_URL`, defined in a `.env` file located at the root of the repository. If your application uses a different configuration approach, you may need to adjust the hook script accordingly.

**Info: How the hook works** When Claude Code runs a subagent, it creates a new folder (e.g., `.claude/worktrees/feature-developer`). This script automatically copies your main `.env` into that folder, asks Neon to branch your database, and updates the `DATABASE_URL`. By the time Claude starts writing code, it is securely connected to a completely isolated database sandbox.

## Step 2: Create subagents with reusable roles

To get the most value out of Claude Code's subagents, it's best to design them with reusable roles across multiple features and optimizations.

For this guide, you will create two reusable roles: a `feature-developer` and a `data-optimizer`.

First, ensure the agents directory exists in your workspace:

```bash
mkdir -p .claude/agents
```

### Subagent 1: The Feature developer

This agent is designed to handle end-to-end feature creation. Create a new file at `.claude/agents/feature-developer.md` and add the following content:

```yaml
---
name: feature-developer
description: Expert full-stack engineer for building new features from scratch. Handles schema changes, API implementation, and tests. Use proactively when asked to build a new feature.
tools: [Read, Write, Edit, Bash, Grep, Glob]
isolation: worktree
background: true
permissionMode: bypassPermissions
---
You are a senior full-stack developer. Your job is to implement new features end-to-end.

When invoked with a feature request:
1. Plan the database schema changes required and apply migrations (e.g., `npx prisma db push`).
2. Implement the backend logic and API routes for the feature.
3. Write a small script or test suite to seed data and verify the feature works.
4. Ensure you don't break existing codebase patterns.
5. Report back with a summary of the files changed, the database schema additions, and the test results.
```

The `isolation: worktree` property instructs Claude to place this agent in its own isolated Git worktree. The `background: true` property allows the agent to run asynchronously, freeing up your main terminal while it works.

Additionally, the `permissionMode` parameter specifies how the subagent handles permission prompts. It can be set to `default`, `acceptEdits`, `dontAsk`, `bypassPermissions`, or `plan` depending on your preference. Since each subagent in this workflow operates in a fully isolated Git worktree and a dedicated Neon database branch, it is safe to use `bypassPermissions`. This allows the agent to execute commands and make database changes without pausing to ask for approval, as any modifications are strictly confined to its isolated environment.

You can learn more about the different supported parameters in the [Claude Code subagents documentation](https://code.claude.com/docs/en/sub-agents#supported-frontmatter-fields).

### Subagent 2: The Data optimizer

This agent acts as a database specialist. You can reuse it anytime you encounter slow queries or technical debt that needs addressing. Create another file at `.claude/agents/data-optimizer.md`:

```yaml
---
name: data-optimizer
description: Database performance and refactoring specialist. Use proactively to fix N+1 query issues, add indexes, or optimize data structures.
tools: [Read, Write, Edit, Bash, Grep, Glob]
isolation: worktree
background: true
permissionMode: bypassPermissions
---
You are a database optimization expert. Your goal is to improve application performance safely.

When invoked with an optimization task:
1. Identify missing indexes, inefficient schemas, or slow ORM queries in the specified area.
2. Create and run migrations to add necessary indexes or restructure data without losing existing records.
3. Refactor the application code (Prisma/Drizzle queries) to use the optimized structures.
4. Write a script to verify the performance improvement or the correctness of the refactored queries.
5. Report back with a summary of the schema changes and query improvements.
```

## Step 3: Run the subagents in parallel

Imagine you are looking at your sprint board and you have two tickets to tackle:

1. **Feature:** Build an API Keys management system so users can generate and revoke programmatic access keys.
2. **Tech Debt:** The `UserActivity` feed is loading too slowly because it lacks proper compound indexes on the database side.

You can now orchestrate your subagents to tackle both of these tasks simultaneously. Open your terminal, start Claude Code by typing `claude`, and give it the context of the two tickets:

```text
I have two tickets to build:
1. Build a new "API Keys" feature. Users should be able to generate, view, and revoke API keys.
2. Optimize the UserActivity feed. It's loading slowly, so please add the necessary database indexes and refactor the queries to be faster wherever needed.

Use subagents to complete the work in parallel.
```

Hit enter. Claude Code evaluates the prompt, delegates the tasks to your subagents based on their descriptions, and dispatches them to run in the background.

![Claude Code parallel subagents](https://neon.com/docs/guides/claude-code-parallel-subagents-example.png)

## Step 4: Watch them work in parallel

While your main terminal remains free for you to continue working, a sequence of automated infrastructure provisioning occurs in the background. Here is exactly what is happening in parallel:

| Action         | Feature Developer Subagent                  | Data Optimizer Subagent                            |
| :------------- | :------------------------------------------ | :------------------------------------------------- |
| **Workspace**  | Git creates `.claude/worktrees/api-keys`    | Git creates `.claude/worktrees/optimize-feed`      |
| **Hook Fires** | `post-checkout` hook runs                   | `post-checkout` hook runs                          |
| **DB Branch**  | Neon creates branch `worktree-api-keys`     | Neon creates branch `worktree-optimize-feed`       |
| **Config**     | Writes `.env` with new database branch URL  | Writes `.env` with new database branch URL         |
| **Migration**  | Agent creates tables necessary for API keys | Agent identifies missing indexes on `UserActivity` |
| **Testing**    | Agent seeds test keys & queries             | Agent tests refactored feed query                  |

**Zero collisions:** Because Neon separates compute and storage using copy-on-write technology, branching takes less than a second. The `feature-developer` adding a new table does not conflict with the `data-optimizer` locking the `UserActivity` table to build an index. They operate in completely independent sandboxes, safely isolated from one another.

You can verify this live by logging into your [Neon Console](https://console.neon.tech). You will see your newly provisioned branches corresponding to each subagent's worktree.

![Neon Console branches](https://neon.com/docs/guides/claude-code-parallel-subagents-neon-branches.png)

## Step 5: Reviewing and merging

When the background subagents complete their tasks, they return their findings back to your main Claude Code conversation. Each agent provides a detailed summary of the files they changed, the database schemas they modified, and the test scripts they ran.

![Claude Code subagent reports](https://neon.com/docs/guides/claude-code-parallel-subagents-reports.png)

Because they worked in isolated Git worktrees, their changes are committed to local branches on your machine. If you are using VS Code or a similar Git GUI, you can seamlessly switch to the branches corresponding to each subagent's worktree to review the code:

![VS Code Git branches](https://neon.com/docs/guides/claude-code-parallel-subagents-vscode-branches.png)

Once Claude presents the reports, it will then prompt you to review the changes and ask if you want to merge them into the main branch. This is your opportunity to inspect the code, run the tests they generated, and verify the database changes in their isolated branches before committing to a merge.

To review the changes locally, you can switch to each subagent's branch using your preferred Git GUI or the command line. For instance, assuming your primary branch is `main`, you'll likely see generated branches such as `worktree-api-keys` and `worktree-optimize-feed`. Check out the API Keys branch to inspect the feature:

```bash
git checkout worktree-api-keys
```

From here, you can thoroughly review the code changes, run any generated tests or scripts, and verify the feature's functionality. Afterward, switch over to the `worktree-optimize-feed` branch to inspect the database optimizations and measure their impact on query execution.

Once you're confident in the changes across both isolated environments, return to your main branch. You can then instruct Claude Code to merge the subagents' work or request further refinements.

![Claude Code merge prompt](https://neon.com/docs/guides/claude-code-parallel-subagents-merge-prompt.png)

You can respond to the merge prompt with a simple confirmation:

```text
Yes, please merge both branches into main.
```

Assuming the agents resolved their tasks cleanly, the merge will complete without conflicts.

![Claude Code merge success](https://neon.com/docs/guides/claude-code-parallel-subagents-merge-success.png)

In cases where changes overlap, Claude may prompt you to resolve merge conflicts. However, if your subagents are well-designed and focused on their specific tasks within isolated environments, you should experience minimal to no conflicts.

## Conclusion

You now have a workflow where AI agents can truly operate in parallel, breaking free from the bottlenecks of sequential development.

The root problem of stateful isolation has been solved. By combining **Claude Code subagents** with **Neon's instant Database Branching**, you eliminate the friction of shared infrastructure entirely. Instead of waiting for one agent to finish a task before starting the next, you can dispatch multiple agents simultaneously.

Every agent gets a safe, isolated sandbox where it can run migrations, drop tables, or refactor queries with zero risk of data corruption or code collisions. You simply define the roles, assign the tasks, and let your AI agents build in parallel, freeing you to focus on high-level architecture, strategy, and review.

## Resources

- [Git Worktrees Documentation](https://git-scm.com/docs/git-worktree)
- [Neon Branching](https://neon.com/branching)
- [Git worktrees and Neon Branching](https://neon.com/guides/git-worktrees-neon-branching)
- [Claude Code Documentation](https://code.claude.com/docs)
- [Claude Code subagents](https://code.claude.com/docs/en/sub-agents).
