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

# Consistency

> Learn about consistency settings and versioning in LanceDB tables.

export const RsConsistencyMakeUsersReader = "fn make_users_reader(\n    ids: Vec<i64>,\n    names: Vec<&str>,\n    login_counts: Option<Vec<i64>>,\n) -> Box<dyn RecordBatchReader + Send> {\n    let mut fields = vec![\n        Field::new(\"id\", DataType::Int64, false),\n        Field::new(\"name\", DataType::Utf8, false),\n    ];\n    let mut columns: Vec<Arc<dyn Array>> =\n        vec![Arc::new(Int64Array::from(ids)), Arc::new(StringArray::from(names))];\n\n    if let Some(login_counts) = login_counts {\n        fields.push(Field::new(\"login_count\", DataType::Int64, true));\n        columns.push(Arc::new(Int64Array::from(login_counts)));\n    }\n\n    let schema = Arc::new(Schema::new(fields));\n    let batch = RecordBatch::try_new(schema.clone(), columns).unwrap();\n    let reader = RecordBatchIterator::new(vec![Ok(batch)].into_iter(), schema);\n    Box::new(reader)\n}\n";

export const RsConsistencyCheckoutLatest = "let checkout_writer_db = connect(&db_uri).execute().await.unwrap();\nlet checkout_reader_db = connect(&db_uri).execute().await.unwrap();\nlet checkout_writer_table = checkout_writer_db\n    .create_table(\n        \"consistency_checkout_latest_table\",\n        make_users_reader(vec![1], vec![\"Alice\"], None),\n    )\n    .mode(CreateTableMode::Overwrite)\n    .execute()\n    .await\n    .unwrap();\nlet checkout_reader_table = checkout_reader_db\n    .open_table(\"consistency_checkout_latest_table\")\n    .execute()\n    .await\n    .unwrap();\ncheckout_writer_table\n    .add(make_users_reader(vec![2], vec![\"Bob\"], None))\n    .execute()\n    .await\n    .unwrap();\nlet rows_before_refresh = checkout_reader_table.count_rows(None).await.unwrap();\nprintln!(\"Rows before checkout_latest: {}\", rows_before_refresh);\ncheckout_reader_table.checkout_latest().await.unwrap();\nlet rows_after_refresh = checkout_reader_table.count_rows(None).await.unwrap();\nprintln!(\"Rows after checkout_latest: {}\", rows_after_refresh);\n";

export const TsConsistencyCheckoutLatest = "const checkoutWriterDb = await lancedb.connect(databaseDir);\nconst checkoutReaderDb = await lancedb.connect(databaseDir);\nconst checkoutWriterTable = await checkoutWriterDb.createTable(\n  \"consistency_checkout_latest_table\",\n  [{ id: 1 }],\n  { mode: \"overwrite\" },\n);\nconst checkoutReaderTable = await checkoutReaderDb.openTable(\n  \"consistency_checkout_latest_table\",\n);\nawait checkoutWriterTable.add([{ id: 2 }]);\nconst rowsBeforeRefresh = await checkoutReaderTable.countRows();\nconsole.log(`Rows before checkoutLatest: ${rowsBeforeRefresh}`);\nawait checkoutReaderTable.checkoutLatest();\nconst rowsAfterRefresh = await checkoutReaderTable.countRows();\nconsole.log(`Rows after checkoutLatest: ${rowsAfterRefresh}`);\n";

export const ConsistencyCheckoutLatest = "uri = str(tmp_db.uri)\nwriter_db = lancedb.connect(uri)\nreader_db = lancedb.connect(uri)\nwriter_table = writer_db.create_table(\n    \"consistency_checkout_latest_table\", [{\"id\": 1}], mode=\"overwrite\"\n)\nreader_table = reader_db.open_table(\"consistency_checkout_latest_table\")\n\nwriter_table.add([{\"id\": 2}])\nrows_before_refresh = reader_table.count_rows()\nprint(f\"Rows before checkout_latest: {rows_before_refresh}\")\n\nreader_table.checkout_latest()\nrows_after_refresh = reader_table.count_rows()\nprint(f\"Rows after checkout_latest: {rows_after_refresh}\")\n";

export const RsConsistencyEventual = "let eventual_writer_db = connect(&db_uri).execute().await.unwrap();\nlet eventual_reader_db = connect(&db_uri)\n    .read_consistency_interval(StdDuration::from_secs(3600))\n    .execute()\n    .await\n    .unwrap();\nlet eventual_writer_table = eventual_writer_db\n    .create_table(\n        \"consistency_eventual_table\",\n        make_users_reader(vec![1], vec![\"Alice\"], None),\n    )\n    .mode(CreateTableMode::Overwrite)\n    .execute()\n    .await\n    .unwrap();\nlet eventual_reader_table = eventual_reader_db\n    .open_table(\"consistency_eventual_table\")\n    .execute()\n    .await\n    .unwrap();\neventual_writer_table\n    .add(make_users_reader(vec![2], vec![\"Bob\"], None))\n    .execute()\n    .await\n    .unwrap();\nlet eventual_rows_after_write = eventual_reader_table.count_rows(None).await.unwrap();\nprintln!(\n    \"Rows visible before eventual refresh interval: {}\",\n    eventual_rows_after_write\n);\n";

export const TsConsistencyEventual = "const eventualWriterDb = await lancedb.connect(databaseDir);\nconst eventualReaderDb = await lancedb.connect(databaseDir, {\n  readConsistencyInterval: 3600,\n});\nconst eventualWriterTable = await eventualWriterDb.createTable(\n  \"consistency_eventual_table\",\n  [{ id: 1 }],\n  { mode: \"overwrite\" },\n);\nconst eventualReaderTable = await eventualReaderDb.openTable(\n  \"consistency_eventual_table\",\n);\nawait eventualWriterTable.add([{ id: 2 }]);\nconst eventualRowsAfterWrite = await eventualReaderTable.countRows();\nconsole.log(\n  `Rows visible before eventual refresh interval: ${eventualRowsAfterWrite}`,\n);\n";

export const ConsistencyEventual = "from datetime import timedelta\n\nuri = str(tmp_db.uri)\nwriter_db = lancedb.connect(uri)\nreader_db = lancedb.connect(uri, read_consistency_interval=timedelta(seconds=3600))\nwriter_table = writer_db.create_table(\n    \"consistency_eventual_table\", [{\"id\": 1}], mode=\"overwrite\"\n)\nreader_table = reader_db.open_table(\"consistency_eventual_table\")\nwriter_table.add([{\"id\": 2}])\nrows_after_write = reader_table.count_rows()\nprint(f\"Rows visible before eventual refresh interval: {rows_after_write}\")\n";

export const RsConsistencyStrong = "let strong_writer_db = connect(&db_uri).execute().await.unwrap();\nlet strong_reader_db = connect(&db_uri)\n    .read_consistency_interval(StdDuration::from_secs(0))\n    .execute()\n    .await\n    .unwrap();\nlet strong_writer_table = strong_writer_db\n    .create_table(\n        \"consistency_strong_table\",\n        make_users_reader(vec![1], vec![\"Alice\"], None),\n    )\n    .mode(CreateTableMode::Overwrite)\n    .execute()\n    .await\n    .unwrap();\nlet strong_reader_table = strong_reader_db\n    .open_table(\"consistency_strong_table\")\n    .execute()\n    .await\n    .unwrap();\nstrong_writer_table\n    .add(make_users_reader(vec![2], vec![\"Bob\"], None))\n    .execute()\n    .await\n    .unwrap();\nlet strong_rows_after_write = strong_reader_table.count_rows(None).await.unwrap();\nprintln!(\n    \"Rows visible with strong consistency: {}\",\n    strong_rows_after_write\n);\n";

export const TsConsistencyStrong = "const strongWriterDb = await lancedb.connect(databaseDir);\nconst strongReaderDb = await lancedb.connect(databaseDir, {\n  readConsistencyInterval: 0,\n});\nconst strongWriterTable = await strongWriterDb.createTable(\n  \"consistency_strong_table\",\n  [{ id: 1 }],\n  { mode: \"overwrite\" },\n);\nconst strongReaderTable = await strongReaderDb.openTable(\n  \"consistency_strong_table\",\n);\nawait strongWriterTable.add([{ id: 2 }]);\nconst strongRowsAfterWrite = await strongReaderTable.countRows();\nconsole.log(`Rows visible with strong consistency: ${strongRowsAfterWrite}`);\n";

export const ConsistencyStrong = "from datetime import timedelta\n\nuri = str(tmp_db.uri)\nwriter_db = lancedb.connect(uri)\nreader_db = lancedb.connect(uri, read_consistency_interval=timedelta(0))\nwriter_table = writer_db.create_table(\n    \"consistency_strong_table\", [{\"id\": 1}], mode=\"overwrite\"\n)\nreader_table = reader_db.open_table(\"consistency_strong_table\")\nwriter_table.add([{\"id\": 2}])\nrows_after_write = reader_table.count_rows()\nprint(f\"Rows visible with strong consistency: {rows_after_write}\")\n";

You can set `read_consistency_interval` on the connection to control how often reads check for updates from other writers.

There are three possible settings for `read_consistency_interval`:

1. **Unset (default)**: no automatic cross-process refresh checks.
2. **Zero seconds**: check for updates on every read (strongest freshness).
3. **Non-zero interval**: check for updates after the interval elapses (eventual refresh).

The value you set depends on your application's consistency needs and performance requirements.
For example, a real-time dashboard might require strong consistency, while a batch analytics job might be
fine with eventual consistency. Stronger consistency is not free — the smaller the interval, the more
often each read pays the cost of refreshing against object storage, which raises per-read latency and cost.

This setting works for both local ([LanceTable](/tables-and-namespaces#understanding-tables)) and remote
tables. It only affects read operations —
write operations are always consistent.

<Callout color="blue">
  **Consistency in Remote Tables**

  For remote tables (`db://` connections), `read_consistency_interval` is also
  respected by the client. The interval is sent to the server as a freshness bound on each read:

  * **Unset (default)**: no freshness header is sent; reads use the server's cached view of the table.
  * **Zero seconds**: every read asks the server for the latest committed version.
  * **Non-zero interval**: reads accept data at least as fresh as `now - interval`.

  In addition, after any write or after a `checkout_latest` / `restore` on a table handle, subsequent
  reads on that same handle carry a freshness floor so you read your own writes without extra
  configuration. The floor is the later of the configured interval and the moment of the last
  write or refresh, and it is shared across handles to the same table on the same connection.

  Each remote table handle also tracks the highest dataset version it has observed in a read
  response and sends it back with every subsequent read, so successive reads on the same handle
  never observe an older version even when a load balancer routes them to query nodes with
  differently-cached views. `checkout_latest` resets this watermark.

  Stronger consistency is not free — the smaller the interval, the more often each read pays the cost
  of refreshing against storage, which raises per-read latency and cost.

  In <Badge color="red">Enterprise</Badge> deployments, the server-side default freshness is still
  controlled by the cluster-level `weak_read_consistency_interval_seconds` parameter; the client setting
  tightens that bound on a per-connection basis.
</Callout>

## Configure Consistency Parameters

To set strong consistency, set the interval to 0:

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

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

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

<Expandable title="In the Rust snippets, a `make_users_reader` helper is used to build Arrow input data.">
  <CodeGroup>
    <CodeBlock filename="Rust" language="Rust" icon="rust">
      {RsConsistencyMakeUsersReader}
    </CodeBlock>
  </CodeGroup>
</Expandable>

For eventual consistency, use a non-zero interval:

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

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

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

With the default unset interval, tables do not auto-refresh from other writers.
To manually check for updates, use `checkout_latest` / `checkoutLatest`:

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

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

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

For reproducible reads, you can also pin a table to a specific snapshot with `checkout(...)` or
a tag, restore a table to a prior version, then return to the live table with
`checkout_latest` / `checkoutLatest`. See
[Versioning](/tables/versioning/) for the full version and tag workflow.

## Handle bad vectors

<Note>
  This section is currently specific to the Python SDK.
</Note>

In LanceDB Python, you can use the `on_bad_vectors` parameter to choose how
invalid vector values are handled. Invalid vectors are vectors that are not valid
because:

1. They are the wrong dimension
2. They contain NaN values
3. They are null but are on a non-nullable field

By default, LanceDB will raise an error if it encounters a bad vector. You can
also choose one of the following options:

* `drop`: Ignore rows with bad vectors
* `fill`: Replace bad values (NaNs) or missing values (too few dimensions) with
  the fill value specified in the `fill_value` parameter. An input like
  `[1.0, NaN, 3.0]` will be replaced with `[1.0, 0.0, 3.0]` if `fill_value=0.0`.
* `null`: Replace bad vectors with null (only works if the column is nullable).
  A bad vector `[1.0, NaN, 3.0]` will be replaced with `null` if the column is
  nullable. If the vector column is non-nullable, then bad vectors will cause an
  error
