Skip to content
GitHubXDiscordRSS

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.

import { AiSearchNamespace } from "alchemy/cloudflare";
const ns = await AiSearchNamespace("production", {
name: "production",
});

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
},
});
src/worker.ts
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);
},
};

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 },
});
src/worker.ts
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);
},
};

Dynamically create isolated instances per tenant without redeployment:

src/worker.ts
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 });
},
};

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,
});

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
},
});
PropertyTypeDefaultDescription
namestringauto-generatedNamespace name (pattern: ^[a-z0-9]([a-z0-9-]{0,26}[a-z0-9])?$)
descriptionstringOptional description (max 256 characters)
deletebooleantrueDelete namespace on removal. Namespace must be empty.
adoptbooleanfalseAdopt existing namespace
PropertyTypeDescription
type"ai_search_namespace"Resource type identifier
idstringStable identifier (equal to namespace)
namespacestringThe namespace name
descriptionstring | nullNamespace description, or null if unset/cleared
createdAtstringCreation timestamp (ISO 8601)

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);
}

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 initially
await AiSearchNamespace("ns", {
name: "docs",
description: "Documentation namespace",
});
// Later: clear the description
await AiSearchNamespace("ns", {
name: "docs",
description: null, // explicit null clears the description
});