Skip to content

How to Use Cloudflare AI Search: Data Sources, Hybrid Retrieval, and Workers Bindings

Aug 29, 2026 1 min
TL;DR Formerly AutoRAG, the managed search primitive: drop files into built-in storage or attach R2 and websites, auto-index with Markdown conversion plus vector and BM25, retrieve with hybrid, RRF, and reranking, and query from Workers via namespace or instance bindings, REST, or MCP.
Table of Contents
  1. What AI Search is and why it is called a search primitive
  2. How data gets in: three sources and the indexing pipeline
  3. Indexing and models: five stages from Markdown conversion to embedding
  4. How to query: vector, keyword, and hybrid
  5. How to connect: five interfaces and two Workers bindings
  6. Limits, pricing, and when not to use it
  7. Overall
  8. Update Log
  9. References

🌏 中文版

If every agent needs search, do you build the vector index, the chunking and sync pipeline, and the BM25 fusion yourself — or reach for a primitive? Cloudflare AI Search is the latter: formerly AutoRAG, now positioned as a managed search primitive. Create an instance, give it data, query it with natural language; the R2, Vectorize, and Workers AI plumbing is handled for you. This post covers how data gets in, how indexing runs, how to tune retrieval, and how to wire it from a Worker — so you can decide when to use the managed path and when to assemble your own.

What AI Search is and why it is called a search primitive

The design pitch is literal: make "searchable" as basic as fetch() in Workers. The docs call it the search primitive for your applications and agents (Overview). It is not another vector database — it is a full pipeline: upload or connect a data source → auto-index and keep it fresh → hybrid retrieval → scored chunks with sources, optionally followed by generation.

How it differs from the usual alternatives:

  • DIY on Vectorize: most flexible — you control chunk size, embedding model, filter extraction, and fallback — but you own crawling, Markdown Conversion, reindexing, and observability. See the on-site Vector Database Comparison.
  • External managed search like Azure AI Search or Algolia: feature-complete, but with an extra hop, separate billing, and data movement out of the Cloudflare edge. AI Search wins on colocation with Workers and the Agents SDK.
  • The old env.AI.autorag(): still works, but marked legacy. New capabilities — built-in storage, namespace bindings, cross-instance search, boost — are only on the new Workers binding. The official upgrade path is Workers binding migration.

Good fits: documentation and knowledge-base search, research tools for agents, per-tenant or per-agent searchable context (e.g., past resolutions per customer in support). Poor fits: teams that need custom chunking, more than five metadata fields per instance, or pinned embedding versions for offline evaluation.

How data gets in: three sources and the indexing pipeline

AI Search ingests from three sources (Data source):

  1. Built-in storage: every instance ships with its own storage and vector index. Upload files via API and they are indexed — no R2 bucket to create first. This is the default since April 2026 and the right choice for dynamic per-agent instances.
  2. R2 Bucket: attach an existing R2 bucket as the source. AI Search syncs it continuously. Use it when your corpus already lives in R2.
  3. Website: attach a domain you own. AI Search crawls it with Browser Rendering and supports discover and sitemap Parse types.

File types are two-tiered: plain text (.md, .json, .csv, .py, .go, etc.) indexes directly; rich formats (.pdf, .docx, .xlsx, .html, .png/.jpg, etc.) go through Markdown Conversion first — image captioning there uses Workers AI vision models and is billed separately. The per-file limit is 4 MB; oversized files are not indexed and appear in error logs.

Indexing is automatic and continuous (Automated indexing). R2 and Website sources resync on change; built-in storage indexes on upload. The ownership shift matters: built-in files live on AI Search-managed R2 and Vectorize — you no longer need a bucket in your account. The R2 bucket that early AutoRAG created for you is no longer written to and can be removed (see Limits & pricing history).

// Built-in storage: upload and index
const instance = env.AI_SEARCH.get("my-instance");
const item = await instance.items.upload("handbook.pdf", pdfBytes);
// or wait until searchable
const ready = await instance.items.uploadAndPoll("handbook.pdf", pdfBytes);

Indexing and models: five stages from Markdown conversion to embedding

The pipeline is fixed; the models at each stage are configurable (Models):

  1. Image to Markdown (optional): object detection plus captioning.
  2. Embedding: turns chunks and queries into vectors. This is the only model choice locked at instance creation.
  3. Query rewriting (optional): an LLM reformulates the user query for better recall.
  4. Reranking (optional): a cross-encoder re-scores fused results by semantic relevance.
  5. Generation: produces the final answer from retrieved context. The generation model is selectable at creation and can be overridden later in the dashboard or per request.

Providers are either Workers AI models or external models via AI Gateway with your own OpenAI or Anthropic keys (Bring your own keys). Attach a Gateway when creating the instance or switch it under Settings, then pick external models. "Smart Default" lets Cloudflare choose and auto-update; explicit selection pins a model but requires tracking the Supported models lifecycle (Production → Announcement → End of life).

Trade-off: Smart Default saves ops but scores can drift on upgrade; pinning is reproducible but you must follow Release notes and deprecation notices. For Traditional Chinese, generation quality is often steadier with external models — the Gateway integration is the practical bridge.

How to query: vector, keyword, and hybrid

Retrieval is where the recent release changed most (Search modes, Hybrid search, Keyword search).

  • Vector-only: strong on intent, weak on exact terms. Searching ERR_CONNECTION_REFUSED timeout may return generic networking docs instead of the page that literally contains the error code.
  • Keyword-only (BM25): scores by term frequency, rarity, and document length — exact terms win, paraphrases lose.
  • Hybrid: runs both in parallel and fuses. Enable with index_method: { vector: true, keyword: true }; fusion is rrf (Reciprocal Rank Fusion, by rank not score, the default) or max (higher of the normalized scores). Hybrid search docs recommend rrf for most cases. The DIY counterpart and formula are covered in Hybrid Search: BM25 + Vector + RRF.

Tunable parameters (instance-level or per-request override):

  • keyword_tokenizer: porter (stemming, running matches run) or trigram (substring, conf matches configuration, better for code).
  • keyword_match_mode: and (all terms required) or or (any term).
  • reranking: cross-encoder rerank after fusion, e.g. @cf/baai/bge-reranker-base.
  • query_rewrite: rewrites the query for recall.
  • boost_by: boosts ranking by metadata, e.g. timestamp desc for recency, up to 3 fields (Filtering).
  • filters: filter by custom metadata with eq/ne/gt/gte/lt/lte and and/or compounds. Only the first 64 bytes of a string field are indexed — keep filterable keys short.
  • max_num_results (1–50, default 10), match_threshold (0–1, default 0.4), context_expansion (0–3 surrounding chunks).
const instance = await env.AI_SEARCH.create({
  id: "my-instance",
  index_method: { vector: true, keyword: true },
  indexing_options: { keyword_tokenizer: "porter" },
  retrieval_options: { keyword_match_mode: "or" },
  fusion_method: "rrf",
  reranking: true,
  reranking_model: "@cf/baai/bge-reranker-base",
});

// Per-request override and boosting
const hits = await instance.search({
  messages: [{ role: "user", content: "How to fix ERR_CONNECTION_REFUSED?" }],
  ai_search_options: {
    retrieval: {
      retrieval_type: "hybrid",
      fusion_method: "rrf",
      keyword_match_mode: "or",
      max_num_results: 8,
      filters: { category: "runbook" },
      boost_by: [{ field: "timestamp", direction: "desc" }],
    },
    reranking: { enabled: true },
  },
});

The other key primitive is cross-instance search. Shared docs and per-customer history often live in separate instances; the namespace search() merges them into one ranked list:

// From the official support-agent example
const results = await env.SUPPORT_KB.search({
  query: "billing error",
  ai_search_options: { instance_ids: ["product-knowledge", "customer-abc123"] },
});

That avoids two round-trips and lets boost_by and reranking apply after the merge.

How to connect: five interfaces and two Workers bindings

Pick the surface by who calls and when the instance is known:

InterfaceBest forNotes
Workers bindingInside Workers and AgentsLowest latency; namespace and instance bindings
REST APIBackend services outside WorkersAccount API token with AI Search permission
Wrangler CLIOps and one-offswrangler ai-search create/list/delete
Python SDKOffline batches and pipelinesParity with REST, good for crawlers and ETL
DashboardManual setup and inspectionPick Gateways, check index status
MCP server + UI snippetsExpose to models or websitesEvery instance ships with an MCP endpoint and embeddable search

Workers offers two bindings (Workers binding):

Namespace binding ai_search_namespaces — dynamic, for per-customer or per-agent instances:

// wrangler.jsonc
{
  "ai_search_namespaces": [{ "binding": "SUPPORT_KB", "namespace": "support" }],
  "ai": { "binding": "AI" }
}
await env.SUPPORT_KB.create({ id: `customer-${customerId}`, index_method: { vector: true, keyword: true } });
const inst = env.SUPPORT_KB.get(`customer-${customerId}`);
await inst.search({ messages: [{ role: "user", content: "What did we try last time?" }] });

Instance binding ai_search — static, bound to a single instance in the default namespace at deploy time, simplest call site:

{ "ai_search": [{ "binding": "MY_SEARCH", "instance_name": "my-instance" }] }
await env.MY_SEARCH.search({ messages: [{ role: "user", content: "What is Cloudflare?" }] });

The legacy env.AI.autorag("my-rag").search({ query }) still works but takes messages (or query) plus ai_search_options and receives no new features. See Workers binding migration and REST API migration.

The recommended Agents SDK pattern is to expose AI Search as a tool (see AI Search: the search primitive for your agents): the model decides when to search_knowledge_base and when to save_resolution (via uploadAndPoll so the next turn is searchable), and uses instance_ids to span shared knowledge and private context.

Limits, pricing, and when not to use it

Hard limits (Limits & pricing, updated 2026-08-26):

LimitWorkers FreeWorkers Paid
Instances per account1005,000
Namespaces per account100100
Files per instance100,0001,000,000 (500,000 with hybrid)
Max file size4 MB4 MB
Queries per month20,000Unlimited
Instances per cross-instance request1010
Pages crawled per day500Unlimited
Custom metadata fields5 per instance5 per instance
Metadata per vector10 KiB (incl. overhead)10 KiB
Filterable string prefixFirst 64 bytesFirst 64 bytes

Pricing: free within limits during open beta; Workers AI and AI Gateway are billed separately. Storage, vector indexing, and website crawling via Browser Rendering are included. Older invoices with separate R2/Vectorize line items are pre-migration history.

When not to use it:

  • You need custom chunking, overlap, or multi-granularity indexing (AI Search chunking is fixed).
  • You need more than five filterable metadata fields or filtering on long strings (only the first 64 bytes are filterable).
  • You need pinned embedding/reranker versions for long-horizon evaluation (Smart Default drifts; explicit choices still face the Model lifecycle).
  • Files frequently exceed 4 MB (e.g., scanned books) — pre-split before upload.

Conversely, if the job is "hybrid search over a corpus with exact-term hits, dynamic per-tenant instances, and minimal ops," the managed trade is compelling. The same build-vs-buy note closes the on-site Hybrid Search piece: use managed to save ops, build on Vectorize for full control over filter extraction and degradation.

Overall

The increment is not "can do RAG" — it is "RAG without the dirty work as a primitive": built-in storage per instance, auto-sync for Website and R2 sources, hybrid retrieval with boost_by and filters tunable per request, and namespace bindings plus cross-instance search that make multi-tenant and multi-agent isolation cheap.

Start with one ai_search instance (minimal config), validate recall and match_threshold, then compare vector vs keyword vs hybrid with reranking; only move to ai_search_namespaces and instance_ids when you need tenancy. A concrete next step tonight: take a corpus you already have (e.g., src/content/posts/), create a test instance on a Paid account, upload 50 documents to built-in storage, query the same questions with the three retrieval types, and log scoring_details (vector_score/keyword_score/fusion_method) before choosing a default.

Update Log

  • 2026-08-30: Added the post to the Cloudflare AI Stack series and kept the Edge Platform reading path through additionalSeries.

References