Skip to content
Discord Get Started

Branching Workflows

DB9 can create a branch of any database — an independent copy with its own credentials, connection string, and data. Branches are useful for preview environments, isolated testing, safe schema migrations, and data recovery.

This guide shows how to create, use, and manage branches through the CLI and SDK.

  • A DB9 account with the CLI installed (see Quick Start)
  • An existing database to branch from
Terminal
db9 create --name production

When you create a branch, DB9 clones schema and data from the source database into a new, independent database. The branch gets its own:

  • TiKV keyspace (isolated storage)
  • Admin credentials
  • Connection string
  • Lifecycle (create, delete independently of the parent)

Changes to the branch do not affect the parent, and changes to the parent do not propagate to the branch.

Branch creation is asynchronous — the command returns immediately with status CLONING, and you poll until the branch reaches ACTIVE.

  1. Create a Branch

    Terminal
    db9 branch create production --name feature-auth

    The command returns immediately with the branch details:

    Output
    Name: feature-auth
    State: CLONING
    Parent: production

    Wait for the branch to be ready

    Poll the branch status until it reaches ACTIVE:

    Terminal
    db9 db status feature-auth

    Or in a script:

    Terminal
    while true; do
    state=$(db9 db status feature-auth --json | jq -r .state)
    if [ "$state" = "ACTIVE" ]; then
    echo "Branch is ready"
    break
    elif [ "$state" = "CREATE_FAILED" ]; then
    echo "Branch creation failed"
    db9 db status feature-auth --json | jq .state_reason
    exit 1
    fi
    sleep 2
    done

    Show credentials on creation

    Terminal
    db9 branch create production --name staging --show-secrets
    # Or individually:
    db9 branch create production --name staging --show-password --show-connection-string

    --show-secrets is shorthand for --show-password --show-connection-string. This prints the admin password and connection string in the output. Avoid this in CI logs — use db9 db connect-token instead for short-lived credentials.

  2. Connect to a Branch

    A branch is a regular DB9 database. Connect with any PostgreSQL tool:

    Terminal
    db9 db connect feature-auth

    Or get the connection string:

    Terminal
    db9 db status feature-auth --json | jq -r .connection_string

    Then use it with psql, your ORM, or any PostgreSQL driver.

  3. List Branches

    Terminal
    db9 branch list production

    Shows all branches of a database with their state and creation time. Supports --output json and --output csv for programmatic use.

  4. Delete a Branch

    Terminal
    db9 branch delete feature-auth

    Deletion is permanent — there is no undo or trash. Deleting a branch does not affect the parent database.

  5. SDK Usage

    Use the TypeScript SDK for programmatic branch management:

    TypeScript
    import { createDb9Client } from 'get-db9';
    const client = createDb9Client();
    // Create a branch (first argument is the parent database ID)
    const branch = await client.databases.branch('production-db-id', {
    name: 'feature-auth'
    });
    console.log(branch.id, branch.state); // "CLONING"
    // Poll until ready
    let status;
    do {
    status = await client.databases.get(branch.id);
    if (status.state === 'CREATE_FAILED') throw new Error(status.state_reason);
    await new Promise(r => setTimeout(r, 2000));
    } while (status.state !== 'ACTIVE');
    // Use the branch — it has its own connection string
    console.log(status.connection_string);
    // Delete when done
    await client.databases.delete(branch.id);

Create a branch per pull request for integration testing:

Terminal
BRANCH_NAME="pr-${PR_NUMBER}"
# Create branch from production
db9 branch create production --name "$BRANCH_NAME"
# Wait for it
while [ "$(db9 db status "$BRANCH_NAME" --json | jq -r .state)" != "ACTIVE" ]; do
sleep 2
done
# Run migrations and tests against the branch
db9 db sql "$BRANCH_NAME" -f migrations/latest.sql
npm test -- --database-url="$(db9 db status "$BRANCH_NAME" --json | jq -r .connection_string)"
# Clean up
db9 branch delete "$BRANCH_NAME"

Test a migration in an isolated branch before applying it:

Terminal
# Branch production
db9 branch create production --name migration-test
# Wait for ready
# ...
# Apply migration
db9 db sql migration-test -f migrations/0042_add_index.sql
# Validate
db9 db sql migration-test -q "SELECT count(*) FROM users"
db9 db sql migration-test -q "EXPLAIN SELECT * FROM users WHERE email = 'test@example.com'"
# If satisfied, apply to production
db9 db sql production -f migrations/0042_add_index.sql
# Clean up test branch
db9 branch delete migration-test

Give each agent task its own database branch so parallel agents don’t interfere with each other:

Terminal
TASK_ID="task-$(uuidgen | head -c 8)"
db9 branch create shared-db --name "$TASK_ID"
# ... wait for ACTIVE ...
# Agent works against isolated branch
db9 db sql "$TASK_ID" -q "CREATE TABLE scratch (id SERIAL, data JSONB)"
db9 db sql "$TASK_ID" -q "INSERT INTO scratch (data) VALUES ('{\"result\": \"done\"}')"
# Clean up when task completes
db9 branch delete "$TASK_ID"
  • Asynchronous creation — branches are not immediately ready. Always poll for ACTIVE state before connecting.
  • Full data copy — branch creation clones both schema and data from the parent.
  • Max 2 concurrent branch creations — attempting a third returns a 429 error. Wait for in-progress branches to finish.
  • Branches count toward database quota — anonymous accounts are limited to 5 databases total (including branches). Run db9 claim to remove the limit.
  • No automatic merge — there is no built-in way to merge branch changes back to the parent. Export and re-apply manually.
  • Deletion is permanent — deleted branches cannot be recovered.
  • Branch naming — names must be unique within your account and cannot be empty.