diff --git a/docs/snippets/tables.mdx b/docs/snippets/tables.mdx
index baee1cb..5c531e1 100644
--- a/docs/snippets/tables.mdx
+++ b/docs/snippets/tables.mdx
@@ -122,6 +122,8 @@ export const PyVersioningRollback = "table.restore(version_after_mod)\nversions
export const PyVersioningTags = "# Create a tag pointing at a specific version\ntable.tags.create(\"baseline\", 1)\ntable.tags.create(\"with-edits\", table.version)\n\n# List all tags on this table\nprint(table.tags.list())\n\n# Look up the version a tag points at\nprint(table.tags.get_version(\"baseline\"))\n\n# Move an existing tag to a different version\ntable.tags.update(\"baseline\", 2)\n\n# Check out a version by tag name\ntable.checkout(\"baseline\")\nprint(table.version)\n\n# Delete a tag (does not delete the underlying version)\ntable.tags.delete(\"with-edits\")\n\n# Return to the latest version\ntable.checkout_latest()\n";
+export const PyVersioningBranches = "# Fork a new branch from the latest version of main\nexperiment = table.branches.create(\"experiment\")\nprint(experiment.current_branch()) # \"experiment\"\n\n# Writes on the branch handle do not affect main\nexperiment.add([{\"author\": \"Maya\", \"quote\": \"draft idea\"}])\n\n# List all branches on the table\nprint(table.branches.list())\n\n# Reopen an existing branch later (writable handle that tracks the branch tip)\nexperiment = table.branches.checkout(\"experiment\")\n\n# Pin a branch to a specific version (read-only view of that version)\nsnapshot = table.branches.checkout(\"experiment\", version=2)\n\n# Open a branch directly from the connection\nexperiment = db.open_table(\"my_table\", branch=\"experiment\")\n\n# Delete a branch when you're done with it\ntable.branches.delete(\"experiment\")\n";
+
export const PyVersioningUpdateData = "table.update(where=\"author='Richard'\", values={\"author\": \"Richard Daniel Sanchez\"})\nrows_after_update = table.count_rows(\"author = 'Richard Daniel Sanchez'\")\nprint(f\"Rows updated to Richard Daniel Sanchez: {rows_after_update}\")\n";
export const TsAddColumnsCalculated = "// Add a discounted price column (10% discount)\nawait schemaAddTable.addColumns([\n {\n name: \"discounted_price\",\n valueSql: \"cast((price * 0.9) as float)\",\n },\n]);\n";
@@ -218,6 +220,8 @@ export const TsVersioningRollback = "await table.checkout(versionAfterMod);\nawa
export const TsVersioningTags = "const tags = await tagsTable.tags();\n\n// Create a tag pointing at a specific version\nawait tags.create(\"baseline\", 1);\nawait tags.create(\"with-edits\", await tagsTable.version());\n\n// List all tags on this table\nconsole.log(await tags.list());\n\n// Look up the version a tag points at\nconsole.log(await tags.getVersion(\"baseline\"));\n\n// Move an existing tag to a different version\nawait tags.update(\"baseline\", 2);\n\n// Check out a version by tag name\nawait tagsTable.checkout(\"baseline\");\nconsole.log(await tagsTable.version());\n\n// Delete a tag (does not delete the underlying version)\nawait tags.delete(\"with-edits\");\n\n// Return to the latest version\nawait tagsTable.checkoutLatest();\n";
+export const TsVersioningBranches = "const branches = await table.branches();\n\n// Fork a new branch from the latest version of main\nconst experiment = await branches.create(\"experiment\");\nconsole.log(experiment.currentBranch); // \"experiment\"\n\n// Writes on the branch handle do not affect main\nawait experiment.add([{ author: \"Maya\", quote: \"draft idea\" }]);\n\n// List all branches on the table\nconsole.log(await branches.list());\n\n// Reopen an existing branch later (writable handle that tracks the branch tip)\nconst tracking = await branches.checkout(\"experiment\");\n\n// Pin a branch to a specific version (read-only view of that version)\nconst snapshot = await branches.checkout(\"experiment\", 2);\n\n// Delete a branch when you're done with it\nawait branches.delete(\"experiment\");\n";
+
export const TsVersioningUpdateData = "await table.update({\n where: \"author = 'Richard'\",\n values: { author: \"Richard Daniel Sanchez\" },\n});\nconst rowsAfterUpdate = await table.countRows(\n \"author = 'Richard Daniel Sanchez'\",\n);\nconsole.log(`Rows updated to Richard Daniel Sanchez: ${rowsAfterUpdate}`);\n";
export const RsAddColumnsCalculated = "// Add a discounted price column (10% discount)\nschema_add_table\n .add_columns(\n NewColumnTransform::SqlExpressions(vec![(\n \"discounted_price\".to_string(),\n \"cast((price * 0.9) as float)\".to_string(),\n )]),\n None,\n )\n .await\n .unwrap();\n";
@@ -318,5 +322,7 @@ export const RsVersioningRollback = "table.checkout(version_after_mod).await.unw
export const RsVersioningTags = "let mut tags = tags_table.tags().await.unwrap();\n\n// Create a tag pointing at a specific version\ntags.create(\"baseline\", 1).await.unwrap();\nlet current_version = tags_table.version().await.unwrap();\ntags.create(\"with-edits\", current_version).await.unwrap();\n\n// List all tags on this table\nlet all_tags = tags.list().await.unwrap();\nprintln!(\"Tags: {:?}\", all_tags);\n\n// Look up the version a tag points at\nlet baseline_version = tags.get_version(\"baseline\").await.unwrap();\nprintln!(\"baseline -> v{}\", baseline_version);\n\n// Move an existing tag to a different version\ntags.update(\"baseline\", 2).await.unwrap();\n\n// Check out a version by tag name (separate method in Rust)\ntags_table.checkout_tag(\"baseline\").await.unwrap();\nprintln!(\"Current version: {}\", tags_table.version().await.unwrap());\n\n// Delete a tag (does not delete the underlying version)\ntags.delete(\"with-edits\").await.unwrap();\n\n// Return to the latest version\ntags_table.checkout_latest().await.unwrap();\n";
+export const RsVersioningBranches = "// Fork a new branch from the latest version of main\nlet experiment = table.create_branch(\"experiment\", None, None).await.unwrap();\nprintln!(\"{:?}\", experiment.current_branch()); // Some(\"experiment\")\n\n// List all branches on the table\nlet all_branches = table.list_branches().await.unwrap();\nprintln!(\"Branches: {:?}\", all_branches);\n\n// Reopen an existing branch later (writable handle that tracks the branch tip)\nlet tracking = table.checkout_branch(\"experiment\", None).await.unwrap();\n\n// Pin a branch to a specific version (read-only view of that version)\nlet snapshot = table.checkout_branch(\"experiment\", Some(2)).await.unwrap();\n\n// Delete a branch when you're done with it\ntable.delete_branch(\"experiment\").await.unwrap();\n";
+
export const RsVersioningUpdateData = "table\n .update()\n .only_if(\"author = 'Richard'\")\n .column(\"author\", \"'Richard Daniel Sanchez'\")\n .execute()\n .await\n .unwrap();\nlet rows_after_update = table\n .count_rows(Some(\"author = 'Richard Daniel Sanchez'\".to_string()))\n .await\n .unwrap();\nprintln!(\n \"Rows updated to Richard Daniel Sanchez: {}\",\n rows_after_update\n);\n";
diff --git a/docs/tables/versioning.mdx b/docs/tables/versioning.mdx
index 61fd91e..0dcde53 100644
--- a/docs/tables/versioning.mdx
+++ b/docs/tables/versioning.mdx
@@ -35,6 +35,9 @@ import {
PyVersioningTags as VersioningTags,
TsVersioningTags as TsVersioningTags,
RsVersioningTags as RsVersioningTags,
+ PyVersioningBranches as VersioningBranches,
+ TsVersioningBranches as TsVersioningBranches,
+ RsVersioningBranches as RsVersioningBranches,
RsVersioningMakeQuotesReader as RsVersioningMakeQuotesReader,
} from '/snippets/tables.mdx';
@@ -218,6 +221,56 @@ Deleting a tag only removes the label, not the version it points to. After
deletion, the underlying table version becomes eligible for cleanup again.
+## Branches
+
+Branches are isolated, writable lines of history forked from another branch
+(or a specific version of one). Use them when you need to experiment with
+schema or data changes, run an A/B compaction strategy, or stage a backfill
+without affecting readers on `main`. Conceptually they sit next to tags:
+**tags label a single version**, while **branches let history diverge** from
+that point.
+
+The branch manager supports the standard operations — `create`, `list`,
+`checkout`, `delete` — and `checkout` / `create` return a new table handle
+scoped to the branch. Writes on that handle do not touch `main`. The
+original handle keeps pointing at the branch it was opened on, which is
+reported by `current_branch()` (`null` / `None` for `main`).
+
+
+
+ {VersioningBranches}
+
+
+
+ {TsVersioningBranches}
+
+
+
+ {RsVersioningBranches}
+
+
+
+In Python, you can also open a branch directly from the connection by
+passing `branch=` to `open_table()`. Combine it with `version=` to open a
+read-only handle pinned to a specific version on that branch:
+
+```python
+# Latest version of the experiment branch (writable)
+experiment = db.open_table("my_table", branch="experiment")
+
+# Pinned to v3 of the experiment branch (read-only)
+snapshot = db.open_table("my_table", branch="experiment", version=3)
+```
+
+
+Each branch handle has its own freshness state and version pin, so reopening
+a branch on a new connection — or restoring one from a pickled handle —
+keeps you on the branch instead of silently reverting to `main`.
+
+Branches are supported by tables backed by the Lance format directly and by
+remote tables served by LanceDB Enterprise.
+
+
## Delete Data From the Table
Let's demonstrate how deletions also create new versions: