Cloudflare AI Search Can Index R2 Files Without Renaming
Cloudflare AI Search now indexes extensionless R2 files with valid Content-Type metadata. See which ingestion steps you can remove.

Cloudflare AI Search removed a filename problem from R2 ingestion on September 11, 2026. If your documents live under stable keys with no extension, you can now keep those keys and make the objects searchable by storing a supported HTTP Content-Type with each one.
That can retire a renaming stage from your ingestion workflow. It does not retire metadata cleanup, indexing, or the check that proves a document actually made it into search.
What actually changed
Cloudflare AI Search is a managed search service for your own content. One way to feed it is an R2 bucket, which is Cloudflare's object storage. AI Search reads the bucket, converts supported documents into searchable text, and builds the index used when your app sends a query.
Until this update, the safe detection path depended on the filename extension. A key such as manual.pdf tells the indexer what it is. A stable key such as documents/manual-alpha does not.
AI Search can now use the extensionless object's ordinary HTTP Content-Type instead. application/pdf says the bytes are a PDF. text/markdown says they are Markdown. Cloudflare also lists text/plain, application/json, text/html, and text/csv among its supported types.
Filename extensions have not gone away. Cloudflare still calls a recognized extension its preferred, faster detection path. The new path matters when changing the key would break URLs, database references, tenant mappings, signatures, or an upload contract you already run.
There is one distinction worth getting right. Content-Type is HTTP metadata on the R2 object. It is not the custom metadata AI Search uses for filters such as category, customer, or document status. Those custom fields ride in x-amz-meta-* headers and need a schema in AI Search. Adding x-amz-meta-content-type does not replace the real HTTP field.
This update changes source ingestion, the point where a document enters the index. It does not change the model that writes an answer after retrieval. The GLM-5.3 Flash update sits at that later generation stage.
The business change is one less naming system
Opaque keys are common for a reason. A product may use a stable database ID as the R2 key so the object can change without changing its address. A document service may avoid exposing a customer's original filename. A signed URL may depend on the exact key.
The old workaround was to create an extension-bearing name for the search copy or add a renaming stage before AI Search saw the object. That creates another identity to store, reconcile, and clean up.
The update lets the original key stay put when its HTTP metadata is already correct. That is the useful workflow reduction.
Here is the before and after ingestion-work estimate. This is a process model, not a measured benchmark or a promised saving.

The table is deliberately not a dollar claim. Cloudflare did not publish a time saving for this feature, and the release does not rewrite existing metadata for you.
What the remaining work costs
AI Search is free during its open beta within the limits of your Workers plan. Storage and vector indexing are included. Workers AI and AI Gateway usage can still be billed separately, but this ingestion change does not alter those rates.
Metadata repair can touch the R2 bill. ListObjects, PutObject, and CopyObject count as Class A operations. HeadObject and GetObject, which a repair tool may use to inspect or read an object, count as Class B operations.
For Standard storage, Class A requests cost $4.50 per million after the monthly free allowance of 1 million. Infrequent Access has no free tier and prices Class A requests at $9.00 per million. It can also charge $0.01 per GB when objects are read or copied.
That gives you the honest budget rule. An object with a correct Content-Type needs no rename-specific repair. An object with the wrong value may still need a write or copy, depending on the tool you use. Count those operations before you schedule a bucket-wide cleanup.
Scale matters on the AI Search side too. The per-instance limit is 100,000 files on Workers Free. Workers Paid allows 1 million files, or 500,000 when hybrid search is enabled. The 4 MB file limit stays the same on both plans.
Who can use this tomorrow
A solo SaaS founder with stable upload IDs
Keep the R2 key your database already stores, then make the uploader attach the real MIME type when it writes the object. Your support search can ingest the same object without a second filename column or a batch job that creates search copies.
The payoff is fewer identities to reconcile when a customer replaces, deletes, or moves a document. The upload still needs to reject a generic binary type when the object is supposed to become searchable.
A platform engineer with a legacy bucket
List extensionless objects with their HTTP metadata, compare each value with Cloudflare's supported MIME types, and isolate the failures. Repair a small sample before touching the whole bucket.
The payoff is a bounded migration. You spend the repair budget only on objects that need it, while keys with valid metadata move straight to a sync and verification pass.
A multi-tenant product team
Keep opaque object keys that do not leak original filenames, and set Content-Type from a trusted server-side check during upload. Apply AI Search path filters or prefixes separately when each tenant needs its own indexing boundary.
The payoff is architectural consistency. Storage identity stays independent from file presentation, while the indexer still gets a type it can validate.
An agency operating client knowledge bases
Separate the two metadata jobs in your runbook. HTTP Content-Type decides whether an extensionless file can be ingested. Custom x-amz-meta-* fields decide how indexed results can be filtered after you define their schema.
The payoff is cleaner debugging. When a document is missing, the team checks ingestion metadata before changing filter rules or the answer model.
Put an extensionless object into the supported path
Cloudflare's R2 Workers API accepts request headers as httpMetadata. The following Worker keeps the request path as the object key and rejects uploads that arrive without Content-Type.
Bind an R2 bucket as DOCS in wrangler.jsonc:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "r2-document-upload",
"main": "src/index.ts",
"compatibility_date": "2026-09-11",
"r2_buckets": [
{
"binding": "DOCS",
"bucket_name": "your-bucket"
}
]
}Then use this Worker:
interface Env {
DOCS: R2Bucket;
}
export default {
async fetch(request, env): Promise<Response> {
if (request.method !== "PUT") {
return new Response("Method Not Allowed", { status: 405 });
}
const key = new URL(request.url).pathname.replace(/^\//, "");
const contentType = request.headers.get("content-type");
if (!key || !contentType) {
return new Response("Key and Content-Type are required");
}
await env.DOCS.put(key, request.body, {
httpMetadata: request.headers,
});
return new Response(`Stored ${key}`);
},
} satisfies ExportedHandler<Env>;Run npx wrangler dev, set WORKER_URL to the local address Wrangler prints, then upload a local PDF to an extensionless destination:
curl "$WORKER_URL/documents/manual-alpha" \
--request PUT \
--header "Content-Type: application/pdf" \
--data-binary @manual.pdfThis example proves the storage part. It does not prove indexing. For production, add authorization, derive the type from trusted inspection rather than a user's filename alone, and compare it with Cloudflare's supported list.
The honest part: successful upload does not mean searchable
R2 writes are strongly consistent, so the object and its metadata are visible after a successful write. AI Search indexing is a separate asynchronous job. A sync request can be accepted and the item can still fail later.
R2-backed instances sync every 6 hours by default. You can choose an interval of 1, 2, 4, 6, 12, or 24 hours, or start a job yourself:
npx wrangler ai-search jobs create <INSTANCE_NAME>Manual source syncs can run at most once every 30 seconds. More retries do not repair bad metadata.
Check item logs, item details, or instance stats after the job. unsupported_type is the relevant item-level error when AI Search cannot accept the detected file type. Fix the object, then sync that item or the source again.
You are unaffected if every R2 key already has a recognized extension. You are also unaffected if your AI Search source is a website or built-in storage rather than an external R2 bucket. This change does not make an unsupported format or an oversized file indexable.
What to do on Monday
Start with an audit, not a bulk rewrite.
Find the skipped extensionless objects
List R2 objects with
httpMetadataincluded, paginate untiltruncatedis false, and isolate keys whose last path segment has no extension. Cross-check those keys against AI Search item logs andunsupported_typefailures.Classify the metadata
Separate supported MIME types from missing, malformed, unsupported, and
application/octet-streamvalues. Keep customx-amz-meta-*fields out of this check because they solve a different problem.Repair a small import
Choose a small, representative set across the formats you actually store. Write or copy each object with the correct HTTP
Content-Type, keeping the original key where your tooling allows it.Sync and prove retrieval
Trigger one source sync. Wait for the items to finish, inspect their logs, then search for a known phrase inside each document. A green storage write is not the finish line. A returned source passage is.
Widen only after the proof
Estimate the Class A and Class B operations your repair method will create, confirm the R2 storage class, and then expand the batch. Update the uploader at the same time so new extensionless objects arrive with supported metadata.
Act this week if stable or opaque R2 keys have forced you to maintain a second naming path for AI Search. Wait if your existing objects lack trustworthy type information, because you need a classification plan before a rewrite. Do nothing if recognized extensions already carry your ingestion path cleanly.
If you want the next platform change translated into an operator decision, join the newsletter.
- Last Updated
- Sep 12, 2026
- Category
- Explained







