How to Branch Your Database

Open inAnthropic

What you'll achieve

By the end of this guide, you will know how to create, switch, diff, merge, and delete branches in TerminusDB using the HTTP API, TypeScript, and Python.

This guide shows you how to work with branches in TerminusDB — create isolated workspaces, make changes, review diffs, and merge back to main. Every operation includes HTTP API, TypeScript, and Python examples.

Git branch for data

Branching in TerminusDB works exactly like git branch — create a lightweight branch, make changes in isolation, then merge back when ready. Branches share history until they diverge, making them cheap to create.

Prerequisites

  • TerminusDB running on localhost:6363 — see installation guide
  • A database with a schema. Examples use admin/mydb with a Product class. Set up:
# Create the database
curl -u admin:root -X POST http://localhost:6363/api/db/admin/mydb \
  -H "Content-Type: application/json" \
  -d '{"label": "My Database"}'

# Add a Product schema class
curl -u admin:root -X POST \
  "http://localhost:6363/api/document/admin/mydb?graph_type=schema&author=setup&message=Add+schema" \
  -H "Content-Type: application/json" \
  -d '{"@type": "Class", "@id": "Product", "name": "xsd:string", "price": "xsd:decimal", "category": "xsd:string"}'

1. Create a new branch

Create a branch from the current head of main. The new branch shares all existing history and diverges from this point forward.

HTTP API

curl -u admin:root -X POST http://localhost:6363/api/branch/admin/mydb/local/branch/feature \
  -H "Content-Type: application/json" \
  -d '{"origin": "admin/mydb/local/branch/main"}'

Expected response:

Example: JSON
{"@type":"api:BranchResponse","api:status":"api:success"}
Example: TypeScript
import TerminusClient from "@terminusdb/terminusdb-client";

const client = new TerminusClient.WOQLClient("http://localhost:6363", {
  user: "admin",
  key: "root",
  organization: "admin",
  db: "mydb",
});

await client.branch("feature");
// Branch "feature" created from current head of main

2. List all branches

See all branches in your database.

HTTP API

curl -u admin:root "http://localhost:6363/api/db/admin/mydb?branches=true"

Expected response:

Example: JSON
{"path": "admin/mydb", "branches": ["feature", "main"]}
Example: TypeScript
// List branches by fetching db info
const info = await client.getDatabase("mydb");
console.log(info.branches);
// ["feature", "main"]

3. Switch to a branch

There is no "checkout" command — you simply target a different branch path in your API calls. Every TerminusDB API path includes the branch:

  • main: /api/document/admin/mydb/local/branch/main
  • feature: /api/document/admin/mydb/local/branch/feature

HTTP API

# Read documents from main
curl -u admin:root "http://localhost:6363/api/document/admin/mydb/local/branch/main?type=Product&as_list=true"

# Read documents from feature branch — just change the path
curl -u admin:root "http://localhost:6363/api/document/admin/mydb/local/branch/feature?type=Product&as_list=true"
Example: TypeScript
// Switch branch context for all subsequent operations
client.checkout("feature");

// All operations now target the feature branch
const docs = await client.getDocument({ type: "Product", as_list: true });

4. Make changes on a branch

Insert or update documents on your branch. Changes are isolated — main is unaffected until you merge.

HTTP API

# Insert a new document on the feature branch
curl -u admin:root -X POST \
  "http://localhost:6363/api/document/admin/mydb/local/branch/feature?author=alice&message=Add+Widget+product" \
  -H "Content-Type: application/json" \
  -d '{"@id": "Product/Widget", "@type": "Product", "name": "Widget", "price": 9.99, "category": "tools"}'

Expected response:

Example: JSON
["terminusdb:///data/Product/Widget"]
# Update an existing document on the feature branch
curl -u admin:root -X PUT \
  "http://localhost:6363/api/document/admin/mydb/local/branch/feature?author=alice&message=Update+Widget+price" \
  -H "Content-Type: application/json" \
  -d '{"@id": "Product/Widget", "@type": "Product", "name": "Widget", "price": 14.99, "category": "tools"}'

Expected response:

Example: JSON
["terminusdb:///data/Product/Widget"]
Example: TypeScript
client.checkout("feature");

// Insert
await client.addDocument(
  { "@type": "Product", "name": "Widget", "price": 9.99, "category": "tools" },
  { author: "alice", message: "Add Widget product" }
);

// Update
await client.updateDocument(
  { "@id": "Product/Widget", "@type": "Product", "name": "Widget", "price": 14.99, "category": "tools" },
  { author: "alice", message: "Update Widget price" }
);

5. Compare a branch to main (diff)

See exactly what changed on your branch compared to main — a structural, field-level diff.

HTTP API

curl -u admin:root -X POST http://localhost:6363/api/diff/admin/mydb \
  -H "Content-Type: application/json" \
  -d '{"before_data_version": "main", "after_data_version": "feature"}'

Expected response:

Example: JSON
[
  {
    "@insert": {
      "@id": "Product/Widget",
      "@type": "Product",
      "name": "Widget",
      "price": 14.99,
      "category": "tools"
    },
    "@op": "Insert"
  }
]

The diff shows typed operations:

  • Insert — a new document exists on the branch but not on main
  • Delete — a document exists on main but not on the branch
  • SwapValue — a field value changed (when the document already existed on both branches)
Example: TypeScript
const diff = await client.getVersionDiff(
  "admin/mydb/local/branch/main",
  "admin/mydb/local/branch/feature"
);
console.log(JSON.stringify(diff, null, 2));
// Shows field-level changes between branches

6. Merge a branch back to main

Apply all changes from your branch onto main. If both branches modified the same field, the merge fails with a conflict report — no silent overwrites.

HTTP API

curl -u admin:root -X POST http://localhost:6363/api/apply/admin/mydb/local/branch/main \
  -H "Content-Type: application/json" \
  -d '{
    "before_commit": "branch:main",
    "after_commit": "branch:feature",
    "commit_info": {
      "author": "alice@example.com",
      "message": "Merge feature branch: add Widget product"
    }
  }'

Expected response (success):

Example: JSON
{"@type":"api:ApplyResponse","api:status":"api:success"}

If there are conflicts:

Example: JSON
{
  "@type": "api:ApplyResponse",
  "api:status": "api:conflict",
  "api:witnesses": [
    {"@id": "Product/Widget", "price": {"@op": "SwapValue", "@before": 9.99, "@after_left": 12.99, "@after_right": 14.99}}
  ]
}

Conflicts must be resolved manually — TerminusDB never silently picks a winner.

Example: TypeScript
await client.apply(
  "admin/mydb/local/branch/main",    // target
  "branch:main",                     // before (common ancestor)
  "branch:feature",                  // after (source of changes)
  { author: "alice@example.com", message: "Merge feature branch" }
);

7. Delete a branch

Remove a branch after merging. The commits remain in the database history but this branch name no longer reaches them.

HTTP API

curl -u admin:root -X DELETE http://localhost:6363/api/branch/admin/mydb/local/branch/feature

Expected response:

Example: JSON
{"@type":"api:BranchResponse","api:status":"api:success"}
Example: TypeScript
await client.deleteBranch("feature");

Complete workflow example

Here is the full branch workflow end-to-end — create, change, review, merge, clean up:

# 1. Create a feature branch
curl -u admin:root -X POST http://localhost:6363/api/branch/admin/mydb/local/branch/price-update \
  -H "Content-Type: application/json" \
  -d '{"origin": "admin/mydb/local/branch/main"}'

# 2. Make changes on the branch
curl -u admin:root -X POST \
  "http://localhost:6363/api/document/admin/mydb/local/branch/price-update?author=alice&message=Add+new+product" \
  -H "Content-Type: application/json" \
  -d '{"@id": "Product/Gadget", "@type": "Product", "name": "Gadget", "price": 24.99, "category": "electronics"}'

# 3. Review what changed (diff against main)
curl -u admin:root -X POST http://localhost:6363/api/diff/admin/mydb \
  -H "Content-Type: application/json" \
  -d '{"before_data_version": "main", "after_data_version": "price-update"}'

# 4. Merge into main
curl -u admin:root -X POST http://localhost:6363/api/apply/admin/mydb/local/branch/main \
  -H "Content-Type: application/json" \
  -d '{"before_commit": "branch:main", "after_commit": "branch:price-update", "commit_info": {"author": "alice", "message": "Merge price-update into main"}}'

# 5. Clean up the branch
curl -u admin:root -X DELETE http://localhost:6363/api/branch/admin/mydb/local/branch/price-update

Next steps

Was this helpful?