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

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

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

RouteRequestRow
HybridTextrank_by: [field, "HybridText", input] — the gateway runs one ranked query per leg and fuses with RRFHybridText rank operator
Multi-querya queries body — independent legs, fused by the store when rerank_by is setMulti-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_query for a queries or rerank_by body, patch_rows, search_after for cursor or searchAfter, conditional_writes for a patch_condition on 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.embed and a chunked one is embed.chunk; a filter operator is its name, such as Contains.
  • Schema-count limits use the limit name, such as max_vector_fields for 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
esc