Operations
Store capability matrix
Layer serves one API across its configured stores. Each cell below comes from the gateway’s backend capability declaration. Wire protocol matching explains the contract, and how we validate it is below the matrix. Pages with backend-specific content offer a picker when more than one documented backend applies.
Matrix
| Wire feature | turbopuffer |
|---|---|
| Namespace/schema CRUD and listing | supported |
| Row upserts | supported |
| Column upserts | supported |
| Delete by ID | supported |
| Single/batch fetch | supported |
| Dense top-k (ANN) | supported |
| Cosine / squared-Euclidean distance | supported |
| BM25 text rank [1] | supported |
| Explicit native Postgres text fallback | unsupported |
| HybridText rank operator (gateway dense + text RRF) | supported |
| Attribute projection | supported |
| Eq / NotEq / Gt / Gte / Lt / Lte / In; And / Or | supported |
| Not / NotIn filters | supported |
| Contains / ContainsAny filters | supported |
| Regex filters | supported |
| Other filter operators | supported |
| Fuzzy text filters | supported |
| Advanced text rank expressions | supported |
| Multi-vector ANN | supported |
| Sparse rank | unsupported |
| Multiple vector/text fields | supported |
| Multi-query queries body / rerank_by (client-composed hybrid) | supported |
| Ranked cursor / searchAfter | supported |
| Ordered scans | supported |
| Facets | approximateNative wire request only; the optional portable adapter primitive is unavailable. |
| Aggregates / group_by | supported |
| Delete by filter | approximateNative wire request only; the optional portable adapter primitive is unavailable. |
| Row patches | supported |
| Column patches | supported |
| Conditional writes | supported |
| Copy namespace | supported |
| Branch namespace | supported |
| Vendor encryption controls | supported |
| Arrow IPC import | unsupported |
| Export formats | supported |
| Backend warm hints | supported |
| Backend stability / watermark signals | supported |
| Backend snapshot integration | supported |
| UDF discovery / writeback primitives | supported |
| Arbitrary vendor administrative passthrough | supported |
| Embedding expressions / schema | supported |
| Query by stored vector ID | supported |
| as_of / between filters | supported |
| Fused leg provenance | supported |
| Auto query routing | supported |
| Query scatter/gather | supported |
| Wire vector encoding | supported |
[1] BM25-class scoring; tokenization differs; fused order may differ across backends
Schema limits
The schema_limits block of the capabilities report: whether a schema attribute may declare embed, and how many attributes of each indexed shape one namespace may declare. A blank count is no store-imposed limit.
| Limit | turbopuffer |
|---|---|
embed — schema attribute may declare embed | supported |
max_gateway_embed_attributes — attributes with a gateway-served embed | |
max_full_text_search_fields — full_text_search fields | |
max_vector_fields — vector fields ([N]f32) |
Blobs
Where blob bytes live. A store with native bytes holds blobs up to max_value_bytes (blank is the gateway's 10 MiB cap); larger blobs, and every blob on a store without native bytes, go to S3.
| Blobs | turbopuffer |
|---|---|
native — the store holds blob bytes | yes |
max_value_bytes — largest blob in the store | 6291456 |
Reading the cells
Supported means the declared feature is available. Approximate means
it is served with the limits described in the cell. Unsupported means the
store cannot serve that feature and returns 422 UnsupportedByStore.
Capabilities describe individual features, not every combination of options.
The schema limits table beneath the matrix gives the numeric
bounds behind the multiple-fields row.
Two request shapes express hybrid retrieval, and each has its own row. A store accepts Supported routes and Approximate routes within their stated limits. Unsupported routes reject.
| Route | Request | Row |
|---|---|---|
HybridText | rank_by: [field, "HybridText", input] — the gateway runs one ranked query per leg and fuses with RRF | HybridText rank operator |
| Multi-query | a queries body — independent legs, fused by the store when rerank_by is set | Multi-query |
On Postgres, HybridText is approximate — served only with the shape its
cell states (fuzziness: 0, no cursor or temporal filter) — and a queries
or rerank_by body returns 422 UnsupportedByStore naming multi_query.
How we validate it
Matching the wire does not promise identical index internals, latency, scores, or ranking across stores. In particular, full-text ranking is backend-specific. Layer’s additional request fields, routes, and response metadata are documented as gateway enhancements.
- API and client contracts. The SDK harness compares the gateway OpenAPI operations and generated Python client with the upstream API, and checks captured HTTP requests against documented examples using a mock server. These checks catch route, field, and serialization drift; they do not prove that a real backend returns the right results.
- Backend acceptance. Store-specific suites send requests through a real gateway and backend using generated clients. They check supported operations and explicit rejection of unsupported requests. The Postgres suite runs against the Compose database.
- Documented examples. A committed selection of upstream examples runs against a real gateway and store. Each request is classified as ok, unsupported, fail, or blocked by a prerequisite. A baseline change fails the check for review; matching a baseline can still preserve known failures. This is a selected test corpus, not proof that every upstream request or combination works.
The matrix is generated from backend declarations and checked for source drift. It states the contract; acceptance results are evidence of behavior. Both are needed to assess compatibility.
The fail-fast contract
Unsupported requests fail with 422 UnsupportedByStore. The gateway does not
silently drop unsupported predicates or substitute a different backend. The
body names the store, the route, and the rejected feature:
{
"error": "UnsupportedByStore",
"store": "pgvector",
"route": "/v2/namespaces/traces",
"feature": "patch_rows",
"message": "UnsupportedByStore: pgvector: patch_rows"
}
feature is a stable identifier. Match on it; do not parse message.
- A wire-feature id from the matrix when one owns the request:
multi_queryfor aqueriesorrerank_bybody,patch_rows,search_afterforcursororsearchAfter,conditional_writesfor apatch_conditionon Postgres. The same string appears in the matrix and the 422. - Otherwise the rejected wire key, dotted when nested: a second embedded
attribute on Postgres is
schema.embedand a chunked one isembed.chunk; a filter operator is its name, such asContains. - Schema-count limits use the limit name, such as
max_vector_fieldsfor a second vector attribute on Postgres.
message stays human-readable and starts with
UnsupportedByStore: {store}: {feature}; any detail follows after a colon.
feature is additive, so existing clients that read error and message
are unaffected, and clients ignore values they do not know. A rejection that
names no single feature carries no feature field.
from hevlayer import AsyncHevlayer, HevlayerError
try:
await client.write_namespace("traces", body)
except HevlayerError as e:
if e.error == "UnsupportedByStore" and e.feature == "multi_query":
... # choose the HybridText route instead