Storage Options and Credential Vending#
LanceDB supports dynamic cloud storage credential management through a mechanism called credential vending — where a namespace server supplies short-lived credentials that are automatically refreshed before they expire. This is critical for long-running operations on remote storage (S3, GCS, etc.) where static credentials would time out mid-operation.
Architecture Overview#
Storage options (credentials, endpoint configuration, region, etc.) flow from two possible sources:
- Static — passed once at connect time via
storage_optionson the connection request. These are stored inListingDatabaseOptions.storage_optionsand inherited by all tables opened through the database. - Dynamic (vended) — supplied by a
StorageOptionsProvidertrait (imported fromlance_io::object_store) that LanceDB calls to retrieve fresh credentials on demand. The provider is wired into anObjectStoreParamsvia the private helperset_storage_options_provider, which wraps both the static initial options and the provider in aStorageOptionsAccessor.
On OpenTableBuilder, the public entry point is storage_options_provider(), which sets the provider for read operations. A parallel method exists for write operations on CreateTableBuilder.
vend_input_storage_options#
vend_input_storage_options is a namespace client property (not a function) set on DirectoryNamespace to instruct the namespace server to return storage credentials alongside table metadata. Three related properties control the behavior :
| Property | Description |
|---|---|
vend_input_storage_options | Set "true" to enable credential return in responses |
vend_input_storage_options_refresh_interval_millis | How often (in ms) the namespace rotates credentials |
refresh_offset_millis | Buffer (e.g. "1000") so credentials aren't flagged expired the instant they're issued |
When enabled, the namespace adds an expires_at_millis timestamp field to returned storage options. LanceDB uses this timestamp to decide when to re-call the provider .
Credential Expiration and Refresh Flow#
- Table open —
describe_tableis called on the namespace, returning storage options withexpires_at_millis. - Read / write — The
StorageOptionsAccessorchecks whether the timestamp has passed before each object store operation. - Refresh — When expired, the accessor calls the provider, which in turn calls
describe_tableagain on the namespace.describe_tablecall count is a measurable signal for credential refresh . - Caching — Credentials are cached per operation to avoid redundant refreshes .
Integration tests test_namespace_credential_refresh_on_read and test_namespace_credential_refresh_on_write verify end-to-end refresh by setting a 3-second expiry and asserting that describe_table is called exactly once after expiry.
A unit test test_manifest_enabled_vend_input_storage_options confirms the expires_at_millis field is present in the options returned by latest_storage_options().
Inspecting Storage Options (Python API)#
The Python Table class exposes two methods :
initial_storage_options()— returns the static options passed at connection/table setup.latest_storage_options()— calls the provider if one is configured, returning the most recent credentials. Use this in credential-vending scenarios.
Both are marked as internal APIs and their return values are subject to change.
Remote URI Scheme Routing#
URI routing happens in ListingDatabase::connect_with_options(). The flow:
- Parse —
url::Url::parse(uri)extracts the scheme . - Windows path guard — single-character schemes (drive letters like
C:) are routed toSelf::open_path(). - Query extraction —
engineandmirrored_storequery params are stripped before passing the URI downstream; remaining params are preserved . - Commit engine rewrite — If an
engineparam is present, the scheme is rewritten as{scheme}+{engine}(e.g.,s3+ddb://) to engage an alternative commit store . - Dispatch —
ObjectStore::from_uri_and_params()(fromlance) receives the cleaned URI and routess3://,gs://,az://,hf://, and other schemes to their respective backend implementations .
Static storage options are passed into this call via ObjectStoreParams.storage_options_accessor . There is no LanceDB-level special casing for hf://; it is handled entirely by the Lance ObjectStore layer.
Key Files#
| File | Purpose |
|---|---|
rust/lancedb/src/database/listing.rs | URI parsing, scheme routing, ListingDatabaseOptions |
rust/lancedb/src/connection.rs | OpenTableBuilder, set_storage_options_provider, vend tests |
python/python/lancedb/table.py | initial_storage_options() / latest_storage_options() Python API |
python/python/tests/test_namespace_integration.py | Credential refresh integration tests, create_tracking_namespace helper |