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/mydbwith aProductclass. 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:
{"@type":"api:BranchResponse","api:status":"api:success"}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 mainfrom terminusdb_client import Client
client = Client("http://localhost:6363")
client.connect(user="admin", key="root", db="mydb")
client.branch("feature")
# Branch "feature" created from current head of main2. 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:
{"path": "admin/mydb", "branches": ["feature", "main"]}// List branches by fetching db info
const info = await client.getDatabase("mydb");
console.log(info.branches);
// ["feature", "main"]# The Python client provides a branches property
branches = client.get_all_branches()
for branch in branches:
print(branch)
# {"name": "main", ...}, {"name": "feature", ...}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"// 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 });# Switch branch context
client.checkout("feature")
# All operations now target the feature branch
docs = client.get_all_documents()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:
["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:
["terminusdb:///data/Product/Widget"]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" }
);client.checkout("feature")
# Insert
client.insert_document(
{"@type": "Product", "name": "Widget", "price": 9.99, "category": "tools"},
commit_msg="Add Widget product"
)
# Update
client.update_document(
{"@id": "Product/Widget", "@type": "Product", "name": "Widget", "price": 14.99, "category": "tools"},
commit_msg="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:
[
{
"@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)
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 branchesdiff = client.diff_version("main", "feature")
for change in diff:
print(change)
# {"@id": "Product/Widget", "price": {"@op": "SwapValue", "@before": 9.99, "@after": 14.99}}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):
{"@type":"api:ApplyResponse","api:status":"api:success"}If there are conflicts:
{
"@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.
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" }
);client.checkout("main")
client.apply(
before_commit="admin/mydb/local/branch/main",
after_commit="admin/mydb/local/branch/feature",
commit_msg="Merge feature branch: add Widget product",
author="alice@example.com"
)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/featureExpected response:
{"@type":"api:BranchResponse","api:status":"api:success"}await client.deleteBranch("feature");client.delete_branch("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-updateNext steps
- Version Control Operations Reference — full HTTP API reference for all version control operations
- Diff & Patch — deeper dive into structural diffing
- Time Travel — query the database at any historical commit
- WOQL Common Patterns — practical query recipes