Use Connection, Table, Query, and Index for common operations.
Use History, Branch, Maintenance, Metadata, SchemaEvolution,
and Blob for the other operations. LanceDB.connect calls
Connection.connect.
API model
The public API uses typed connection and table handles, reusable queries and schemas, and error and write result structs. These guides describe the current source; see installation for release status.
alias LanceDB.{Batch, Query, Schema, Table}
{:ok, db} = LanceDB.connect("./data/vectors")
schema = Schema.new(id: :int64, text: :string, vector: {:vector, 3})
{:ok, table} = LanceDB.Connection.create_empty_table(db, "documents", schema)
{:ok, %LanceDB.WriteResult{inserted: 1}} =
Table.add(table, [%{id: 1, text: "Elixir", vector: [1.0, 0.0, 0.0]}])
query = table |> Query.new() |> Query.nearest_to([1.0, 0.0, 0.0]) |> Query.limit(20)
{:ok, rows} = Query.all(query)
rows = query |> Query.stream(batch_size: 256) |> Enum.to_list()
{:ok, plan} = Query.explain(query)
{:ok, arrow_schema} = Query.schema(query)
{:ok, output_schema} = LanceDB.ArrowSchema.to_schema(arrow_schema)
{:ok, target} = LanceDB.Connection.create_empty_table(db, "copy", output_schema)
{:ok, %LanceDB.WriteResult{inserted: copied}} =
LanceDB.Table.add(
target,
LanceDB.Source.batches(Query.stream_batches(query)),
commit: :once
)
[batch | _] = Enum.to_list(Query.stream_batches(query))
{:ok, ipc} = Batch.to_ipc(batch)
{:ok, imported_batches} = Batch.from_ipc(ipc)Query.all/1 reads all results immediately. Query.stream/2 reads results
on demand. Both use the same query options. Scans have a default limit of
100 rows. Searches have a default limit of 10 rows. Use
Query.limit(query, nil) to remove a scan limit.
A repeated query against a live handle can read new data. Use
LanceDB.History.snapshot/2 to select a fixed version without changing the
source handle.
Operation failures return {:error, %LanceDB.Error{kind: kind}}. A stream
failure raises LanceDB.Error when the caller reads the stream. Match error
kinds instead of message text. Incorrect API arguments raise ArgumentError. Result rows have string field names. User metadata and raw statistics have
string keys.
Fixed API results use structs with atom fields.
LanceDB.Execution.configure(reads: 64, writes: 16) sets native operation
limits for the whole BEAM VM. Read cursors keep a read slot until they
close. If no slot is available, the operation returns :busy. Separate
write slots let cursors supply data to ingestion. These settings limit
concurrent operations. They do not limit memory for each query.
Database execution emits telemetry spans. Builders and direct in-memory inspection helpers do not. Start and stop events share an operation ID. Failures use stable error kinds.
Quick start
{:ok, db} = LanceDB.connect("./data/vectors")
{:ok, table} =
LanceDB.Connection.create_table(db, "documents", [
%{id: "1", text: "Elixir and OTP", category: "code", vector: [1.0, 0.0, 0.2]},
%{id: "2", text: "Sourdough bread", category: "food", vector: [0.0, 1.0, 0.8]}
])
{:ok, matches} =
LanceDB.Query.search(table, [0.9, 0.1, 0.2],
limit: 5,
distance: :cosine,
filter: "category = 'code'"
)
# Results are maps with string keys, including a numeric "_distance".
IO.inspect(matches)
{:ok, %LanceDB.WriteResult{inserted: 1}} =
LanceDB.Table.add(table, [
%{id: "3", text: "Phoenix LiveView", category: "code", vector: [0.9, 0.1, 0.3]}
])
{:ok, 3} = LanceDB.Table.count_rows(table)
{:ok, 2} = LanceDB.Table.count_rows(table, "category = 'code'")
{:ok, %LanceDB.Schema{fields: fields}} = LanceDB.Table.schema(table)
{:ok, ["documents"]} = LanceDB.Connection.table_names(db)
{:ok, reopened} = LanceDB.Connection.open_table(db, "documents")
{:ok, %LanceDB.WriteResult{}} = LanceDB.Table.delete(reopened, "id = '3'")
# Permanently remove the table:
{:ok, :dropped} = LanceDB.Connection.drop_table(db, "documents")connect/0 uses "./lancedb" by default. Connections and tables are native
resource handles. The BEAM garbage collector releases these handles. Native
operations share a Tokio runtime. Connect, table open, cursor requests, job
waits, and writer cleanup run native waits on Tokio and reply by message,
leaving BEAM schedulers available. Many other native calls use dirty schedulers
and can retain one while waiting for storage.
Connections accept :timeout_ms and session cache budgets in the third
argument to connect/3. Table opening accepts its own deadline and per-open
cache budgets. See table-open controls
for options, cancellation limits, and Table.cache_stats/1.
For application-supervised handle retention and shared background index
warming, use LanceDB.TableCache. Its returned handles work with the usual
table and query APIs. See table caching for configuration,
status, eviction and explicit invalidation.
Records and search
Records use maps with atom or string keys. To create a table without an explicit schema, provide a non-empty list. Its first record determines the schema:
- Strings, signed 64-bit integers, floats, and booleans become scalar columns.
- Non-empty numeric lists become fixed-size float32 vector columns.
- Later rows can contain null scalar values. The first row cannot.
- All rows must have the same fields and compatible types.
- Vectors must have consistent dimensions and values representable as float32.
- Define an explicit schema for lists and nested maps. Schema inference does not infer them.
Appends and upserts validate records against the stored schema, as described
above. Without :vector_column, search selects the unique column compatible
with the search mode and query dimension. Multiple matches require an explicit
column; dimension mismatches report the query and expected dimensions.
Supply your own embeddings.
Search supports :l2 (default), :cosine, and :dot distances for floating
vectors, and :hamming for uint8 vectors. It
accepts a positive :limit (default 10) and an optional SQL :filter. SQL
predicates pass directly to LanceDB. Construct these expressions safely.
Table creation defaults to mode: :create. This mode fails if the table
exists. mode: :exist_ok opens an existing table without appending the
supplied records. mode: :overwrite replaces the table.
Database operations return {:ok, value} or {:error, reason}. Invalid search
options or creation modes raise ArgumentError. Malformed records return
an error tuple. Table inspection returns logical %LanceDB.Schema{} values.
Query and batch inspection return %LanceDB.ArrowSchema{} descriptions.
Both contain %LanceDB.Field{} values.
Before creation, convert physical descriptions with
ArrowSchema.to_schema/1. This API does not expose LanceDB Cloud.
Telemetry
The package sends operation events automatically through :telemetry:
[:lancedb, :operation, :start]: System time and operation metadata.[:lancedb, :operation, :stop]: Duration in native time units and:okor:errorstatus.[:lancedb, :operation, :exception]: Duration and standard exception metadata.
Coverage includes connect, add, delete, update, upsert, and
merge. It also includes immediate query and diagnostic execution, plus
query stream open, next, and close calls. A stream has timings for
individual native calls. It has no single span across consumer work.
Standard span context links start and stop events. An execution_id
associates open, next, and close calls across each enumeration.
Immediate queries also attach parent_operation_id. Re-enumeration and
public calls from callbacks get independent execution IDs. Convenience
methods enter their canonical span once. Successful events do not include
records, SQL, credentials, or table handles. Exception metadata can contain
user data in reasons or stacktraces.
The optional table cache emits operation spans for cache_fetch,
cache_prewarm, cache_status, and its cache_connect, cache_open, and
cache_warm workers. Worker metadata includes cache_id, table_name,
generation, and index_names. It also emits per-index completion/failure and
entry eviction events; see cache telemetry.
For per-session index and metadata cache counters, use
LanceDB.Table.cache_stats/1. It requires no metrics recorder and reports the
session actually used by the table. See cache statistics
for shared-session scope and fields. The following metrics instead accumulate
across all connections in the native library. Native storage metrics are opt-in:
:ok = LanceDB.Telemetry.enable_native_metrics() # before opening connections
catalog = LanceDB.Telemetry.catalog()
series = LanceDB.Telemetry.snapshot()
:ok = LanceDB.Telemetry.poll()poll/0 emits [:lancedb, :native, :metric] events. Scalars have a value
measurement. Histograms have count and sum, with cumulative buckets
in metadata. Metadata also includes the string name, kind, and
attributes. These are cumulative snapshots across the process. Exporters
must not sum repeated counter snapshots or treat histogram sums as
individual observations.
Attribute labels can contain storage paths. Use catalog/0 to discover
metric names and units. New series appear as operations run.
You cannot disable or reset the native recorder. You can install it again
without changes. A conflicting native recorder returns {:error, %LanceDB.Error{}}
with operation :enable_native_metrics. Schedule
poll/0 with your own process or telemetry_poller. The package does not
start a polling process.