> ## Documentation Index
> Fetch the complete documentation index at: https://lancedb-bcbb4faf-mintlify-f5da8d82.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Versioning and Reproducibility

> Learn how to implement versioning and ensure reproducibility in LanceDB. Includes version control, data snapshots, and audit trails.

export const RsVersioningMakeQuotesReader = "fn make_quotes_reader(rows: Vec<(i64, &str, &str)>) -> Box<dyn RecordBatchReader + Send> {\n    let ids: Vec<i64> = rows.iter().map(|(id, _, _)| *id).collect();\n    let authors: Vec<&str> = rows.iter().map(|(_, author, _)| *author).collect();\n    let quotes: Vec<&str> = rows.iter().map(|(_, _, quote)| *quote).collect();\n\n    let schema = Arc::new(Schema::new(vec![\n        Field::new(\"id\", DataType::Int64, false),\n        Field::new(\"author\", DataType::Utf8, false),\n        Field::new(\"quote\", DataType::Utf8, false),\n    ]));\n\n    let batch = RecordBatch::try_new(\n        schema.clone(),\n        vec![\n            Arc::new(Int64Array::from(ids)),\n            Arc::new(StringArray::from(authors)),\n            Arc::new(StringArray::from(quotes)),\n        ],\n    )\n    .unwrap();\n    let reader = RecordBatchIterator::new(vec![Ok(batch)].into_iter(), schema);\n    Box::new(reader)\n}\n";

export const RsBranches = "use lancedb::table::Ref;\n\n// Fork an isolated, writable branch from main's latest version.\n// The returned handle is scoped to the branch; writes on it do not\n// affect main.\nlet branch = branches_table\n    .create_branch(\"exp\", Ref::Version(None, None))\n    .await\n    .unwrap();\nbranch\n    .add(make_quotes_reader(vec![(4, \"Lancelot\", \"For the realm!\")]))\n    .execute()\n    .await\n    .unwrap();\nlet branch_rows = branch.count_rows(None).await.unwrap();\nlet main_rows = branches_table.count_rows(None).await.unwrap();\nprintln!(\"Branch rows: {}\", branch_rows); // 4\nprintln!(\"Main rows: {}\", main_rows); // 3; main is untouched\n\n// List all branches, mapping name to branch metadata.\nlet all_branches = branches_table.list_branches().await.unwrap();\nprintln!(\"Branches: {:?}\", all_branches);\n\n// Reopen the branch later by name, or open it directly via the builder.\nlet checked_out = branches_table.checkout_branch(\"exp\").await.unwrap();\nlet opened = db\n    .open_table(\"quotes_branches_example\")\n    .branch(\"exp\")\n    .execute()\n    .await\n    .unwrap();\nlet checked_out_rows = checked_out.count_rows(None).await.unwrap();\nlet opened_rows = opened.count_rows(None).await.unwrap();\nprintln!(\"Reopened rows: {}, {}\", checked_out_rows, opened_rows); // both 4\n\n// Delete a branch when you're done with it.\nbranches_table.delete_branch(\"exp\").await.unwrap();\n";

export const TsBranches = "const branches = await table.branches();\n\n// Fork an isolated, writable branch from main's latest version.\n// The returned handle is scoped to the branch; writes on it do not\n// affect main.\nconst branch = await branches.create(\"exp\");\nawait branch.add([{ id: 4, author: \"Lancelot\", quote: \"For the realm!\" }]);\nconsole.log(await branch.countRows()); // 4 rows on the branch\nconsole.log(await table.countRows()); // 3 rows; main is untouched\n\n// List all branches, mapping name to branch metadata.\nconsole.log(await branches.list());\n\n// Reopen the branch later by name, or open it directly from the\n// database connection.\nconst checkedOut = await branches.checkout(\"exp\");\nconst branchHandle = await db.openTable(\n  \"quotes_branches_example\",\n  undefined,\n  { branch: \"exp\" },\n);\nconsole.log(await checkedOut.countRows()); // 4\nconsole.log(await branchHandle.countRows()); // 4\n\n// Delete a branch when you're done with it.\nawait branches.delete(\"exp\");\n";

export const Branches = "# Fork an isolated, writable branch from main's latest version.\n# The returned handle is scoped to the branch; writes on it do not\n# affect main.\nbranch = table.branches.create(\"exp\")\nbranch.add([{\"id\": 4, \"author\": \"Lancelot\", \"quote\": \"For the realm!\"}])\nprint(branch.count_rows())  # 4 rows on the branch\nprint(table.count_rows())  # 3 rows; main is untouched\n\n# List all branches, mapping name to branch metadata.\nprint(table.branches.list())\n\n# Reopen the branch later by name, or open it directly from the\n# database connection.\nchecked_out = table.branches.checkout(\"exp\")\nbranch_handle = db.open_table(\"quotes_branches_example\", branch=\"exp\")\nprint(checked_out.count_rows(), branch_handle.count_rows())  # both 4\n\n# Delete a branch when you're done with it.\ntable.branches.delete(\"exp\")\n";

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 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 VersioningTags = "# 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 RsVersioningDeleteData = "table.delete(\"author = 'Morty'\").await.unwrap();\nlet rows_after_deletion = table.count_rows(None).await.unwrap();\nprintln!(\"Number of rows after deletion: {}\", rows_after_deletion);\n";

export const TsVersioningDeleteData = "await table.delete(\"author = 'Morty'\");\nconst rowsAfterDeletion = await table.countRows();\nconsole.log(`Number of rows after deletion: ${rowsAfterDeletion}`);\n";

export const VersioningDeleteData = "table.delete(\"author = 'Morty'\")\nrows_after_deletion = table.count_rows()\nprint(f\"Number of rows after deletion: {rows_after_deletion}\")\n";

export const RsVersioningCheckoutLatest = "table.checkout_latest().await.unwrap();\n";

export const TsVersioningCheckoutLatest = "await table.checkoutLatest();\n";

export const VersioningCheckoutLatest = "table.checkout_latest()\n";

export const RsVersioningRollback = "table.checkout(version_after_mod).await.unwrap();\ntable.restore().await.unwrap();\nlet versions_after_rollback = table.list_versions().await.unwrap();\nlet version_count_after_rollback = versions_after_rollback.len();\nprintln!(\n    \"Total number of versions after rollback: {}\",\n    version_count_after_rollback\n);\n";

export const TsVersioningRollback = "await table.checkout(versionAfterMod);\nawait table.restore();\nconst versionsAfterRollback = await table.listVersions();\nconst versionCountAfterRollback = versionsAfterRollback.length;\nconsole.log(\n  `Total number of versions after rollback: ${versionCountAfterRollback}`,\n);\n";

export const VersioningRollback = "table.restore(version_after_mod)\nversions = table.list_versions()\nversion_count_after_rollback = len(versions)\nprint(f\"Total number of versions after rollback: {version_count_after_rollback}\")\n";

export const RsVersioningListAllVersions = "let all_versions = table.list_versions().await.unwrap();\nfor v in &all_versions {\n    println!(\"Version {}, created at {}\", v.version, v.timestamp);\n}\n";

export const TsVersioningListAllVersions = "const allVersions = await table.listVersions();\nfor (const v of allVersions) {\n  console.log(`Version ${v.version}, created at ${v.timestamp}`);\n}\n";

export const VersioningListAllVersions = "versions = table.list_versions()\nfor v in versions:\n    print(f\"Version {v['version']}, created at {v['timestamp']}\")\n";

export const RsVersioningCheckVersionsAfterMod = "let versions_after_mod = table.list_versions().await.unwrap();\nlet version_count_after_mod = versions_after_mod.len();\nlet version_after_mod = table.version().await.unwrap();\nprintln!(\n    \"Number of versions after modifications: {}\",\n    version_count_after_mod\n);\nprintln!(\"Current version: {}\", version_after_mod);\n";

export const TsVersioningCheckVersionsAfterMod = "const versionsAfterMod = await table.listVersions();\nconst versionCountAfterMod = versionsAfterMod.length;\nconst versionAfterMod = await table.version();\nconsole.log(\n  `Number of versions after modifications: ${versionCountAfterMod}`,\n);\nconsole.log(`Current version: ${versionAfterMod}`);\n";

export const VersioningCheckVersionsAfterMod = "versions = table.list_versions()\nversion_count_after_mod = len(versions)\nversion_after_mod = table.version\nprint(f\"Number of versions after modifications: {version_count_after_mod}\")\nprint(f\"Current version: {version_after_mod}\")\n";

export const RsVersioningAddData = "let more_data = vec![\n    (4, \"Richard Daniel Sanchez\", \"That's the way the news goes!\"),\n    (5, \"Morty\", \"Aww geez, Rick!\"),\n];\ntable\n    .add(make_quotes_reader(more_data))\n    .execute()\n    .await\n    .unwrap();\n";

export const TsVersioningAddData = "const moreData = [\n  {\n    id: 4,\n    author: \"Richard Daniel Sanchez\",\n    quote: \"That's the way the news goes!\",\n  },\n  { id: 5, author: \"Morty\", quote: \"Aww geez, Rick!\" },\n];\nawait table.add(moreData);\n";

export const VersioningAddData = "more_data = [\n    {\n        \"id\": 4,\n        \"author\": \"Richard Daniel Sanchez\",\n        \"quote\": \"That's the way the news goes!\",\n    },\n    {\"id\": 5, \"author\": \"Morty\", \"quote\": \"Aww geez, Rick!\"},\n]\ntable.add(more_data)\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";

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 VersioningUpdateData = "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 RsVersioningCheckInitialVersion = "let versions = table.list_versions().await.unwrap();\nlet current_version = table.version().await.unwrap();\nprintln!(\"Number of versions after creation: {}\", versions.len());\nprintln!(\"Current version: {}\", current_version);\n";

export const TsVersioningCheckInitialVersion = "const versions = await table.listVersions();\nconst currentVersion = await table.version();\nconsole.log(`Number of versions after creation: ${versions.length}`);\nconsole.log(`Current version: ${currentVersion}`);\n";

export const VersioningCheckInitialVersion = "versions = table.list_versions()\ncurrent_version = table.version\nprint(f\"Number of versions after creation: {len(versions)}\")\nprint(f\"Current version: {current_version}\")\n";

export const RsVersioningBasicSetup = "let table_name = \"quotes_versioning_example\";\nlet data = vec![\n    (1, \"Richard\", \"Wubba Lubba Dub Dub!\"),\n    (2, \"Morty\", \"Rick, what's going on?\"),\n    (3, \"Richard\", \"I turned myself into a pickle, Morty!\"),\n];\n\nlet table = db\n    .create_table(table_name, make_quotes_reader(data))\n    .mode(CreateTableMode::Overwrite)\n    .execute()\n    .await\n    .unwrap();\n";

export const TsVersioningBasicSetup = "const tableName = \"quotes_versioning_example\";\nconst data = [\n  { id: 1, author: \"Richard\", quote: \"Wubba Lubba Dub Dub!\" },\n  { id: 2, author: \"Morty\", quote: \"Rick, what's going on?\" },\n  {\n    id: 3,\n    author: \"Richard\",\n    quote: \"I turned myself into a pickle, Morty!\",\n  },\n];\nconst table = await db.createTable(tableName, data, { mode: \"overwrite\" });\n";

export const VersioningBasicSetup = "import pyarrow as pa\n\ndb = tmp_db\n\ntable_name = \"quotes_versioning_example\"\ndata = [\n    {\"id\": 1, \"author\": \"Richard\", \"quote\": \"Wubba Lubba Dub Dub!\"},\n    {\"id\": 2, \"author\": \"Morty\", \"quote\": \"Rick, what's going on?\"},\n    {\n        \"id\": 3,\n        \"author\": \"Richard\",\n        \"quote\": \"I turned myself into a pickle, Morty!\",\n    },\n]\n\n# Define schema\nschema = pa.schema(\n    [\n        pa.field(\"id\", pa.int64()),\n        pa.field(\"author\", pa.string()),\n        pa.field(\"quote\", pa.string()),\n    ]\n)\n\ntable = db.create_table(table_name, data, schema=schema, mode=\"overwrite\")\n";

This page shows the core table-versioning APIs used in the code snippets for Python, TypeScript, and Rust.
Each operation below maps directly to methods shown in the examples.

## Basic Versioning Example

Let's create a table with sample data to demonstrate LanceDB's versioning capabilities:

### Set Up the Table

First, let's create a table with some sample data:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningBasicSetup}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningBasicSetup}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningBasicSetup}
  </CodeBlock>
</CodeGroup>

<Expandable title="Rust helper used in this page">
  <CodeGroup>
    <CodeBlock filename="Rust" language="Rust" icon="rust">
      {RsVersioningMakeQuotesReader}
    </CodeBlock>
  </CodeGroup>
</Expandable>

### Check Initial Version

After creating the table, let's check the initial version information:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningCheckInitialVersion}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningCheckInitialVersion}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningCheckInitialVersion}
  </CodeBlock>
</CodeGroup>

## Modify Data

When you modify data through operations like update or delete, LanceDB automatically creates new versions.

### Update Existing Data

Let's update some existing records to see versioning in action:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningUpdateData}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningUpdateData}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningUpdateData}
  </CodeBlock>
</CodeGroup>

### Add New Data

Now let's add more records to the table:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningAddData}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningAddData}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningAddData}
  </CodeBlock>
</CodeGroup>

### Check Version Changes

Let's see how the versions have changed after our modifications:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningCheckVersionsAfterMod}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningCheckVersionsAfterMod}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningCheckVersionsAfterMod}
  </CodeBlock>
</CodeGroup>

## Rollback to Previous Versions

LanceDB supports fast rollbacks to any previous version without data duplication.

### View All Versions

First, let's see all the versions we've created:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningListAllVersions}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningListAllVersions}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningListAllVersions}
  </CodeBlock>
</CodeGroup>

### Restore a Version Snapshot

Now let's restore a captured version snapshot:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningRollback}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningRollback}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningRollback}
  </CodeBlock>
</CodeGroup>

## Tag-Based Versioning

Numeric table versions like `v3` or `v17` are precise but hard to remember. Tags
let you attach human-readable labels (e.g., `"prod"`, `"baseline"`,
`"q3-evaluation"`) to specific versions and check those out by name. They are
conceptually similar to git tags, and unlike numeric versions, **tagged versions
are preserved when old versions are pruned** (see the cleanup note at the bottom
of this page).

The tags API supports the standard CRUD operations — create, list, update, delete —
plus checking out by tag name.

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningTags}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningTags}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningTags}
  </CodeBlock>
</CodeGroup>

<Note>
  Deleting a tag only removes the label, not the version it points to. After
  deletion, the underlying table version becomes eligible for cleanup again.
</Note>

## Branches

Branches are isolated, writable lines of history forked from another branch (or
a specific version). Writes to a branch do **not** affect `main`, which makes
branches ideal for:

* Running experiments (new indexes, schema changes, reprocessing) without
  disturbing production reads on `main`.
* Backfills or migrations that you want to review before promoting.
* Sharing a frozen point-in-time fork with a collaborator while continuing to
  write to `main`.

Unlike tags, which are read-only labels on existing versions, a branch has its
own writable history. Creating or checking out a branch returns a new table
handle whose reads and writes are scoped to that branch.

<Note>
  Branches are currently supported on local and namespace-backed tables in
  LanceDB OSS. Branch support for LanceDB Enterprise (remote) tables is not yet
  available.
</Note>

### Create, Write, and Reopen a Branch

Create a branch from `main` (the default source) and write to it. The base table
continues to point at `main` and is unaffected by writes on the branch. You can
also reopen an existing branch either from a table handle or directly from the
database connection when opening the table.

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {Branches}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsBranches}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsBranches}
  </CodeBlock>
</CodeGroup>

`list` returns a mapping of branch names to branch metadata, including which
branch each was forked from. `main` is the reserved default branch: wherever a
branch is optional, leaving it out means `main`. To fork from somewhere else,
pass a branch name, a specific version, or both when creating the branch.

Deleting a branch removes that branch and its branch-local history; data on
`main` is not affected. There is no automatic merge operation. To promote
changes, copy the desired data back explicitly.

<Note>
  **Branches vs. tags vs. checkout**

  * Use a **tag** to bookmark an existing version with a human-readable name. Tags
    are read-only and protect that version from cleanup.
  * Use **`checkout(version)`** to read from a historical version of `main`
    without forking. The handle is read-only until you `restore`.
  * Use a **branch** when you need to *write* on top of a point in history
    without touching `main`.
</Note>

## Delete Data From the Table

Let's demonstrate how deletions also create new versions:

### Go Back to Latest Version

First, let's return to the latest version:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningCheckoutLatest}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningCheckoutLatest}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningCheckoutLatest}
  </CodeBlock>
</CodeGroup>

### Delete Data

Now let's delete some data to see how it affects versioning:

<CodeGroup>
  <CodeBlock filename="Python" language="Python" icon="python">
    {VersioningDeleteData}
  </CodeBlock>

  <CodeBlock filename="TypeScript" language="TypeScript" icon="square-js">
    {TsVersioningDeleteData}
  </CodeBlock>

  <CodeBlock filename="Rust" language="Rust" icon="rust">
    {RsVersioningDeleteData}
  </CodeBlock>
</CodeGroup>

### Version History and Operations

On a fresh table, the snippets in this guide produce this version sequence:

1. `v1`: create table (`create_table` / `createTable` / `create_table`)
2. `v2`: update rows (`update`)
3. `v3`: add rows (`add`)
4. `v4`: restore snapshot (`restore`) from `version_after_mod`/`versionAfterMod`
5. `v5`: delete rows (`delete`)

Read-only and checkout operations shown here (`list_versions`/`listVersions`, `version`, `checkout`, `checkout_latest`/`checkoutLatest`) do not create new versions.

The version metadata fields can differ by backend. Direct table-backed version listing exposes a
timestamp, while namespace-backed listing may expose fields such as `manifest_path`,
`manifest_size`, `e_tag`, and `timestamp_millis`. In deployments that use managed versioning,
prefer the table version APIs exposed by LanceDB Enterprise or the namespace service instead of
mixing in lower-level Lance file operations.

<Note>
  **System Operations**

  System operations like `optimize()`, index updates, and table compaction also increment table version numbers.
  In LanceDB OSS and Enterprise, `optimize()` can prune older versions based on its retention setting (`cleanup_older_than`, 7 days by default),
  which is when old-version files are removed and disk space is reclaimed.

  **Tagged versions are exempt from cleanup.** A version with a tag pointing at it is
  retained regardless of age, and its files are not removed by `optimize()`. To make
  a tagged version eligible for pruning, [delete the tag](#tag-based-versioning) first.
</Note>
