AiSearchNamespace
Create and manage Cloudflare AI Search namespaces for grouping and isolating search instances.
The AiSearchNamespace resource creates and manages Cloudflare AI Search namespaces. Namespaces group AI Search instances together, providing logical isolation and scoped access control. Instance names are unique within their namespace.
When used as a Worker binding, AiSearchNamespace provides a ai_search_namespaces binding that gives the Worker dynamic access to all instances within the namespace — enabling runtime creation, deletion, search, and chat operations.
Minimal Example
Section titled “Minimal Example”import { AiSearchNamespace } from "alchemy/cloudflare";
const ns = await AiSearchNamespace("production", { name: "production",});Use as Worker Binding
Section titled “Use as Worker Binding”The primary use case for AiSearchNamespace is as a Worker binding. This gives your Worker dynamic access to all instances in the namespace at runtime:
import { Worker, AiSearchNamespace } from "alchemy/cloudflare";
const ns = await AiSearchNamespace("docs", { name: "docs",});
await Worker("api", { entrypoint: "./src/worker.ts", bindings: { DOCS: ns, // Namespace binding },});export default { async fetch(request, env) { // Access an instance within the namespace. For a one-off lookup the // simpler `query` shape is preferred; use `messages` for multi-turn / // chat-style context. const results = await env.DOCS.get("my-blog").search({ query: "How does caching work?", });
// List all instances in the namespace const instances = await env.DOCS.list();
// Create a new instance at runtime (no redeployment needed). // `index_method` defaults to hybrid (vector + keyword); override for // keyword-only or vector-only indexing. const tenant = await env.DOCS.create({ id: "tenant-123" }); await tenant.items.upload("faq.md", "# FAQ\n\n...");
// Delete an instance await env.DOCS.delete("old-docs");
return Response.json(results); },};Use Cases
Section titled “Use Cases”Multi-language Content
Section titled “Multi-language Content”One instance per language, accessed through a single binding:
import { AiSearchNamespace, Worker } from "alchemy/cloudflare";
const blog = await AiSearchNamespace("blog", { name: "blog" });
await Worker("api", { entrypoint: "./src/worker.ts", bindings: { BLOG: blog },});export default { async fetch(request, env) { const lang = new URL(request.url).searchParams.get("lang") || "en"; const q = new URL(request.url).searchParams.get("q") ?? ""; const results = await env.BLOG.get(`blog-${lang}`).search({ query: q }); return Response.json(results); },};Per-tenant SaaS
Section titled “Per-tenant SaaS”Dynamically create isolated instances per tenant without redeployment:
export default { async fetch(request, env) { const tenantId = request.headers.get("x-tenant-id"); const url = new URL(request.url);
if (url.pathname === "/onboard" && request.method === "POST") { await env.TENANTS.create({ id: `tenant-${tenantId}` }); return new Response("Onboarded"); }
if (url.pathname === "/search") { const results = await env.TENANTS.get(`tenant-${tenantId}`).search({ query: url.searchParams.get("q") ?? "", }); return Response.json(results); }
return new Response("Not found", { status: 404 }); },};With AiSearch Instances
Section titled “With AiSearch Instances”Create instances in a specific namespace using the namespace prop on AiSearch:
import { AiSearch, AiSearchNamespace, R2Bucket } from "alchemy/cloudflare";
const ns = await AiSearchNamespace("production", { name: "production",});
const bucket = await R2Bucket("docs", { name: "my-docs" });
const search = await AiSearch("docs-search", { source: bucket, namespace: ns,});Both Binding Types in One Worker
Section titled “Both Binding Types in One Worker”You can use both namespace bindings (dynamic multi-instance) and single instance bindings (direct access) in the same Worker:
import { Worker, AiSearch, AiSearchNamespace } from "alchemy/cloudflare";
const ns = await AiSearchNamespace("docs", { name: "docs" });const blog = await AiSearch("blog-search", { name: "blog" });
await Worker("api", { entrypoint: "./src/worker.ts", bindings: { DOCS: ns, // Namespace binding — dynamic access BLOG_SEARCH: blog, // Single instance binding — direct access },});Configuration
Section titled “Configuration”| Property | Type | Default | Description |
|---|---|---|---|
name | string | auto-generated | Namespace name (pattern: ^[a-z0-9]([a-z0-9-]{0,26}[a-z0-9])?$) |
description | string | — | Optional description (max 256 characters) |
delete | boolean | true | Delete namespace on removal. Namespace must be empty. |
adopt | boolean | false | Adopt existing namespace |
Output Properties
Section titled “Output Properties”| Property | Type | Description |
|---|---|---|
type | "ai_search_namespace" | Resource type identifier |
id | string | Stable identifier (equal to namespace) |
namespace | string | The namespace name |
description | string | null | Namespace description, or null if unset/cleared |
createdAt | string | Creation timestamp (ISO 8601) |
Type Guard
Section titled “Type Guard”To narrow an unknown binding or resource to an AiSearchNamespace, use isAiSearchNamespace:
import { isAiSearchNamespace } from "alchemy/cloudflare";
if (isAiSearchNamespace(binding)) { // binding is narrowed to AiSearchNamespace console.log(binding.namespace);}Clearing a description
Section titled “Clearing a description”Descriptions follow three-way semantics on update:
- Absent from props (
undefined): leave the current description untouched. Useful when you don’t want to overwrite out-of-band edits made from the Cloudflare dashboard. - String value: set the description to that value.
null: explicitly clear a previously-set description.
// Set initiallyawait AiSearchNamespace("ns", { name: "docs", description: "Documentation namespace",});
// Later: clear the descriptionawait AiSearchNamespace("ns", { name: "docs", description: null, // explicit null clears the description});