Lattice is in preview. It is documented and usable, but it sits outside the
release line: it is not listed in the changelog, its configuration can
change without a deprecation cycle, and it carries no compatibility
promise. The supported way to embed text on CPU is the
[bundled model menu](/docs/ce/api/embed#cpu-models); Lattice is
for workloads that have measured that menu and need something smaller.
Lattice is a static retriever — a token lookup table rather than a transformer.
It embeds text in microseconds on a CPU and adds a few megabytes to a
deployment. It scores materially below a real dense embedder on retrieval, which
is the trade it exists to make.
It is an explicit serving leg. A namespace that selects Lattice never falls back
to another leg, and an unconfigured artifact is a validation error rather than a
silent substitution.
## Provisioning
Generate a deployment artifact with the upstream
[Lattice slicer](https://github.com/ErikKaum/lattice/tree/main/slicer), place
its `model.safetensors` and `tokenizer.json` together, and set
`LAYER_LATTICE_MODEL_PATH` to the model file before starting the gateway. The
supported model id is `erikkaum/lattice-retrieval`; the requested `embed.dims`
must match the loaded artifact, and only text modality is supported.
```bash
uv run slicer slice \
--dim 512 \
--quant int4_row \
--output-dir /var/lib/hevlayer/lattice
export LAYER_LATTICE_MODEL_PATH=/var/lib/hevlayer/lattice/model.safetensors
```
```jsonc
"text": {
"type": "string",
"embed": {
"model": "erikkaum/lattice-retrieval",
"dims": 512,
"serving": { "prefer": "lattice" }
}
}
```
`prefer: lattice` selects the Lattice artifact. `prefer: local` also resolves to
it when the declared model is `erikkaum/lattice-retrieval`.
The recommended operating point is an int4-per-row, 512-dimensional artifact.
Int4 quantizes the model's lookup-table weights only. Layer writes the resulting
normalized vectors as `[512]f32`; Turbopuffer's int8 minimum for quantized
vector storage is a separate choice and is not used by this path.
## End-to-end example
Declare the Lattice profile on a string attribute, write rows, and query with
`Embed`. The gateway embeds both sides in-process — no external inference
provider is involved.
Write two rows into a namespace whose `text` attribute carries the profile
above:
```bash
curl -X POST "$LAYER_GATEWAY_URL/v2/namespaces/articles" \
-H "Authorization: Bearer $LAYER_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"upsert_rows": [
{"id": "planet-1", "title": "Planet",
"text": "Jupiter is the biggest planet in the Solar System."},
{"id": "photo-1", "title": "Photosynthesis",
"text": "Plants turn sunlight, water, and carbon dioxide into food."}
],
"schema": {
"text": {
"type": "string",
"embed": {
"model": "erikkaum/lattice-retrieval",
"dims": 512,
"serving": { "prefer": "lattice" }
}
}
}
}'
```
Query by meaning rather than exact phrase:
```bash
curl -X POST "$LAYER_GATEWAY_URL/v2/namespaces/articles/query" \
-H "Authorization: Bearer $LAYER_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rank_by": ["text", "ANN", ["Embed", "largest planet in the solar system"]],
"top_k": 3,
"include_attributes": ["title", "text"]
}'
```
```jsonc
{
"rows": [
{ "id": "planet-1", "$dist": 0.137, "title": "Planet",
"text": "Jupiter is the biggest planet in the Solar System." }
],
"performance": {
"embedding_tokens": 7,
"embedding_ms": 1 // in-process lookup — no network hop to a provider
}
}
```
A live example of exactly this contract is the
[Wikipedia × Lattice demo](https://wiki.hevlayer.com): all 283,997 Simple
English Wikipedia articles (1.74M paragraph rows) embedded through Lattice and
searched on Turbopuffer, with the `performance` echo displayed beside each
result. Source at [github.com/hev/wiki](https://github.com/hev/wiki).
## Limits
- Text only. An image modality on a Lattice profile is a validation error.
- No [revision pins or instructions](/docs/ce/api/embed#model-settings). Those
extensions require a GPU-served profile.
- `embed.dims` must equal the sliced artifact's dimension. A mismatch is a
validation error at write time, not a silent reshape.
- A directory that fails to load stops the gateway at startup rather than
serving a namespace that cannot embed.
# Response Headers
Source: https://hevlayer.com/docs/ce/api/response-headers
import Edition from "../../../components/docs/Edition.astro";
Layer keeps turbopuffer-compatible read bodies in the upstream shape and
returns Layer-specific metadata in response headers.
| Header | Values | Returned by |
| --- | --- | --- |
| `x-layer-stable-as-of` | Epoch milliseconds | Query, multi-query, scan counts |
| `x-layer-next-cursor` | Opaque cursor token | Single-query pagination |
| `x-layer-warning` | `vector_attribute_dropped` | Query, fetch |
| `traceparent` | W3C trace context | Query, multi-query |
The watermark header can be absent before a stable observation exists.
SDKs expose these headers as fields where that is more convenient. For
example, `query_namespace` returns upstream `rows` and also sets
`stable_as_of` / `next_cursor` on the parsed response object when the
headers are present.
# Turbopuffer passthrough
Source: https://hevlayer.com/docs/ce/api/upstream-features
import PostgresWarning from "../../../components/docs/PostgresWarning.astro";
import ShardingCompare from "../../../components/docs/ShardingCompare.astro";
import StoreMatrixLink from "../../../components/docs/StoreMatrixLink.astro";
These Turbopuffer features pass through Layer unchanged when the store is
Turbopuffer, in Community Edition and Pro. Layer forwards the request and
returns Turbopuffer's response, errors included, so Turbopuffer's
documentation is the reference for each one. Each entry below says how to
reach the feature through the gateway and what Layer adds, if anything.