# Branch a database

> Copy a database and check that changes stay on the branch

> Nevia is in beta and open to selected teams. Public launch in Dec 2026. The CLI installs with `curl -fsSL https://get.nevia.cloud | sh`, and the MCP server is at https://api.nevia.cloud/mcp. A person signs in once in the browser.
> Setup, sign-in and requesting access: [SKILL.md](https://nevia.cloud/SKILL.md). When Nevia fits and when it doesn't: [why.md](https://nevia.cloud/why.md).

> For the complete documentation index, see [llms.txt](https://nevia.cloud/llms.txt). This page's HTML version: https://nevia.cloud/docs/databases/branch

Branch `orders` as `orders-staging` to work on a copy of its data without
touching the source.

You need [the CLI installed and signed in](https://nevia.cloud/docs/get-started/quickstart.md), `psql`, and a
[selected workspace](https://nevia.cloud/docs/workspaces/select.md) where you have the admin or editor
role. Use `orders` from [Create and connect to a database](https://nevia.cloud/docs/databases/create.md).
Keep the name `orders-staging` free.

## Prepare the source

```bash
nevia pg status orders
```

You can branch a `ready` or `sleeping` database with no pending transition or
running operation. The SQL example needs `ready`, so [wake `orders`](https://nevia.cloud/docs/databases/lifecycle.md)
first if it is sleeping. Copying data needs a persistent disk, which the
deployment supplies.

Use a small table to check the copy. If you already have `pings` from the
quickstart, this adds one row:

```bash
psql "$(nevia pg connect orders --uri)" <<'SQL'
CREATE TABLE IF NOT EXISTS pings (id serial PRIMARY KEY, note text);
INSERT INTO pings (note) VALUES ('baseline-a');
SELECT count(*) FROM pings;
SQL
```

Note the row count. A new table has one row. Leave the table alone on the
source until you finish checking the branch.

## Branch

Commit the writes you need, then wait at least five seconds. A running source
can reuse a disk snapshot less than five seconds old, and the branch would miss
newer writes:

```bash
sleep 5
nevia pg branch orders -b orders-staging --wait
nevia pg status orders-staging
```

The branch should be `ready`, with no pending transition and `parent` set to
the ID of `orders`. It has its own host and data disks, and inherits the
source's Postgres version, size, storage and credentials. The source keeps
running; a fresh snapshot briefly freezes its disk writes.

Branch creation doesn't print a password. `pg connect` reads the inherited
password from the branch's machine and returns the connection:

```bash
psql "$(nevia pg connect orders-staging --uri)" -c 'SELECT count(*) FROM pings;'
```

The count should match the source. The query also confirms the branch accepts
TLS connections.

## Check a change

Insert a row on the branch:

```bash
psql "$(nevia pg connect orders-staging --uri)" -c \
  "INSERT INTO pings (note) VALUES ('branch-mutation');"
```

Then count both:

```bash
for db in orders orders-staging; do
  psql "$(nevia pg connect "$db" --uri)" -c 'SELECT count(*) FROM pings;'
done
```

The source count is unchanged. The branch has one more row.

## Clean up

Delete the branch and its data. If you enabled protection on it, clear that
first:

```bash
nevia pg rm orders-staging --yes --wait
```

Deleting `orders` leaves its branches running with their own data. See
[Sleep, wake and delete a database](https://nevia.cloud/docs/databases/lifecycle.md),
[Database lifecycle states](https://nevia.cloud/docs/reference/database-lifecycle.md), and the
[`nevia pg branch` options](https://nevia.cloud/docs/reference/cli/pg/branch.md).
