> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lancedb.com/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 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>

## 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.

<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>
