2.0.0-beta.46 - Vectorize
v2.0.0-beta.46 ships Cloudflare Vectorize as a bindable
resource — index, metadata indexes, and an Effect-native runtime
client — plus an important fix to how the Cloudflare state store
bootstraps.
Cloudflare.VectorizeIndex
Section titled “Cloudflare.VectorizeIndex”A VectorizeIndex is a globally distributed vector database
index. Declare one as a resource, bind it to a Worker, and you
get a typed Effect-native client for inserting and querying
vector embeddings.
const index = yield* Cloudflare.VectorizeIndex("docs", { dimensions: 768, metric: "cosine",});Or pin dimensions and metric to a managed embedding model
with a preset:
const index = yield* Cloudflare.VectorizeIndex("docs", { preset: "@cf/baai/bge-base-en-v1.5",});The index is immutable — dimensions, metric, preset,
and description are all fixed at creation, so changing any of
them triggers a replacement.
Bind it to a Worker
Section titled “Bind it to a Worker”Cloudflare.VectorizeIndex.bind(index) attaches the binding and
hands back a client whose methods — upsert, query,
queryById, insert, deleteByIds, getByIds, describe —
are all yield*-able Effects:
export default class Worker extends Cloudflare.Worker<Worker>()( "Worker", { main: import.meta.filename }, Effect.gen(function* () { const docs = yield* Cloudflare.VectorizeIndex.bind(index);
return { fetch: Effect.gen(function* () { yield* docs.upsert([ { id: "1", values: [0.1, 0.2, 0.3], metadata: { kind: "doc" } }, ]); const matches = yield* docs.query([0.1, 0.2, 0.3], { topK: 5 }); return yield* HttpServerResponse.json({ count: matches.count }); }), }; }).pipe(Effect.provide(Cloudflare.VectorizeIndexBindingLive)),) {}Cloudflare.VectorizeMetadataIndex
Section titled “Cloudflare.VectorizeMetadataIndex”By default you can’t filter a query on a metadata property —
the property has to be indexed first. VectorizeMetadataIndex
declares that index. Point it at a parent index, name the
property, and give its type:
const index = yield* Cloudflare.VectorizeIndex("docs", { dimensions: 768, metric: "cosine",});
yield* Cloudflare.VectorizeMetadataIndex("kind-index", { indexName: index.indexName, propertyName: "kind", indexType: "string",});With the metadata index in place (and created before vectors are
inserted), query accepts a filter against that property:
const matches = yield* docs.query([0.1, 0.2, 0.3], { topK: 3, filter: { kind: { $eq: "second" } },});Metadata indexes are immutable too — changing the property name, type, or parent index replaces them.
Thanks David J. Felix and John Royal for the contribution. (#407)
Fix: state-store bootstrap no longer rotates your keys
Section titled “Fix: state-store bootstrap no longer rotates your keys”The bug: updating the state store stack always used a fresh local state, so the auth token — and, worse, the encryption key — rotated on every run. beta.46 fixes the bootstrap to read from remote state, which already holds the auth token and encryption key, so neither is regenerated. You can run
bun alchemy cloudflare bootstrap --forceto force an update of everything against the real state without rotating the keys.
The same change hardens a few adjacent failure modes:
- Decrypt failures degrade gracefully — a failed decrypt now
returns
undefinedinstead of throwing. - Invalid tokens self-heal — an invalid auth token is detected and refreshed.
- Missing store recovers — if the profile thinks the state store exists but it’s actually gone, it’s recreated.
(#477)