Cloudflare offerings (optional integrations)
August 29, 2026 · View on GitHub
kody binds a broad set of Cloudflare offerings. Origin
(packages/worker/wrangler.jsonc) is the largest surface — D1 (APP_DB), KV
(OAUTH_KV, BUNDLE_ARTIFACTS_KV), cross-script Durable Object bindings
(MCP_OBJECT and others), R2 (COMMUNITY_ASSETS, EMAIL_BLOBS,
REPO_SESSION_BLOBS), Images (IMAGES), Workers AI (AI, optionally routed
through AI Gateway via AI_GATEWAY_ID), Vectorize (CAPABILITY_VECTOR_INDEX),
Queues, Analytics Engine (USAGE_EVENTS), Workflows, and worker loaders — but
it is not the whole inventory. Platform, runtime, and jobs wranglers
(packages/platform-worker/wrangler.jsonc,
packages/runtime-worker/wrangler.jsonc, packages/jobs-worker/wrangler.jsonc)
own Durable Object classes, JOBS_DB, and runtime-only bindings. See
architecture and
architecture/data-storage.md before adding,
removing, or replacing a binding.
This guide covers how those common offerings are added, useful when you need another one of:
- R2 (object storage)
- Images (resize / re-encode)
- Workers AI
- AI Gateway
- An additional KV namespace for app data (separate from
OAUTH_KV)
All examples assume you are using this repo's packages/worker/wrangler.jsonc
and that you run commands from the repo root.
Authentication: wrangler login vs API tokens
For local, interactive development:
- Log in once with
npx wrangler login - Wrangler uses browser-based OAuth, and commands run as your user
For CI / GitHub Actions / automation:
- Create a Cloudflare API token and provide it as
CLOUDFLARE_API_TOKEN - Prefer least-privilege, account-scoped tokens (avoid "All accounts")
What token to make (permissions)
Cloudflare's API token UI changes over time, but the shape is stable:
- Token permissions are Account permissions (not Zone permissions)
- You grant Read/Edit per product area
- Wrangler deploys, creates resources, and sets secrets via the API token
Recommended baseline permissions for this repo:
Workers Scripts:Edit(deploy, update, delete preview Workers)Workers KV Storage:Edit(OAuth/session KV)D1:Edit(migrations, database operations)Workers Queues:Edit(email delivery Queue, DLQ, and event subscription)
Add these permissions when you add the corresponding offering:
- R2:
R2 Storage:Edit - Workers AI:
Workers AI:Read(forwrangler ai models; deploy uses Workers Scripts) - AI Gateway (only if you want to manage gateways via API):
AI Gateway:Edit
If you use npx wrangler secret put ... in CI, your token must also be able to
edit Worker secrets (covered by Workers Scripts:Edit).
Images (resize / re-encode)
Use the Images binding for off-isolate raster transforms so a large upload
cannot OOM the Worker. Origin and platform wranglers bind IMAGES; package
icons and integration / MCP logos fit to 256px WebP at ingest.
Token permissions
Images uses the Worker script binding. Deploy is covered by
Workers Scripts:Edit; there is no extra Images resource to create.
Bindings (packages/worker/wrangler.jsonc)
"images": { "binding": "IMAGES" }
Local wrangler and workers-unit tests use the offline Images simulator (width
/ height / fit / format). Wrangler does not inherit the images key into
named environments, so production, preview, and test each restate
"images": { "binding": "IMAGES" }. Node-unit tests use
createFakeImagesBinding() in
packages/worker/src/test-support/images-binding.ts.
R2 (object storage)
Use R2 for file uploads, user-generated media, and other blob/object storage.
Token permissions
R2 Storage:Edit(for creating/listing buckets via Wrangler)
Commands to create buckets
Create separate buckets for production vs preview/testing:
npx wrangler r2 bucket create <app-name>-uploadsnpx wrangler r2 bucket create <app-name>-uploads-previewnpx wrangler r2 bucket list
Wrangler can also update packages/worker/wrangler.jsonc for you:
npx wrangler r2 bucket create <app-name>-uploads --binding UPLOADS_BUCKET --env production --update-confignpx wrangler r2 bucket create <app-name>-uploads-preview --binding UPLOADS_BUCKET --env preview --update-config
Bind the bucket in packages/worker/wrangler.jsonc
Add an r2_buckets binding in each environment you want to use it:
env.production: bind the production bucketenv.preview/env.test: bind the preview bucket
Example (production):
"r2_buckets": [
{
"binding": "UPLOADS_BUCKET",
"bucket_name": "<app-name>-uploads"
}
],
Example (preview/test):
"r2_buckets": [
{
"binding": "UPLOADS_BUCKET",
"bucket_name": "<app-name>-uploads-preview"
}
],
Local dev notes
npm run dev runs wrangler dev --local, so R2 is emulated locally. To hit
remote R2 from dev, run Wrangler with --remote (for example
node ./wrangler-env.ts dev --remote).
Workers AI
Workers AI lets your Worker call Cloudflare-hosted AI models.
Token permissions
Workers Scripts:Edit(deploy)Workers AI:Read(optional; forwrangler ai models)
Commands to explore models
npx wrangler ai modelsnpx wrangler ai models --json
Bind Workers AI in packages/worker/wrangler.jsonc
Add the AI binding per environment:
"ai": { "binding": "AI" }
If you want the Ai helper client, install it:
npm install @cloudflare/ai
In your Worker code, you typically construct a client like:
import { Ai } from '@cloudflare/ai'
const ai = new Ai(env.AI)
AI Gateway
AI Gateway provides analytics, caching, retries, and controls for calling third-party AI providers (for example OpenAI or Anthropic) from your Worker.
Token permissions
If you create/configure gateways via the dashboard, you do not need any extra token permissions beyond what you already use to deploy Workers.
If you want to manage gateways via API automation, add:
AI Gateway:Edit
Create a gateway
There is no wrangler subcommand for AI Gateway in Wrangler v4. Create the
gateway in the Cloudflare dashboard:
- Cloudflare dashboard ->
AI->AI Gateway - Create a gateway and copy:
- your
account_id - the
gateway_idyou chose/received
- your
Commands to verify the gateway works
AI Gateway uses provider-specific upstream paths. For OpenAI-compatible traffic, the URL looks like:
https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_id>/openai
You can do a quick smoke test with curl (example uses OPENAI_API_KEY):
curl -sS "https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_id>/openai/v1/models" -H "Authorization: Bearer $OPENAI_API_KEY" | head
Using AI Gateway in app code
Most provider SDKs support overriding the base URL:
- Keep the provider API key as a Worker secret (for example
OPENAI_API_KEY) - Point the SDK's base URL at the gateway URL
KV (app KV, separate from OAUTH_KV)
This repo already binds OAUTH_KV for OAuth/session state. Treat OAUTH_KV as
"owned" by @cloudflare/workers-oauth-provider:
- Avoid mixing app data into
OAUTH_KV - Avoid key prefix collisions with the OAuth library
- Keep quotas/evictions isolated from auth state
Token permissions
Workers KV Storage:Edit
Commands to create a second namespace
Create a dedicated namespace for app data, for example APP_KV:
npx wrangler kv namespace create <app-name>-app --binding APP_KV --env production --update-confignpx wrangler kv namespace create <app-name>-app-preview --binding APP_KV --env production --preview --update-config
If you are not using --update-config, record the namespace IDs and add them to
packages/worker/wrangler.jsonc manually (see next section).
Bind the namespace in packages/worker/wrangler.jsonc
Add a second entry in kv_namespaces alongside OAUTH_KV:
"kv_namespaces": [
{
"binding": "OAUTH_KV",
"id": "<oauth-kv-id>",
"preview_id": "<oauth-kv-preview-id>"
},
{
"binding": "APP_KV",
"id": "<app-kv-id>",
"preview_id": "<app-kv-preview-id>"
}
],
If you want a higher-level AI integration
If you're looking for a higher-level way to integrate AI (streaming responses, tool/function calling, typed outputs, and a clean client/server contract), consider TanStack AI.
This repo is not a React app, so the main thing to know is: TanStack AI is framework-agnostic at its core. You can use:
@tanstack/aion the server (Workers) to run models and tools@tanstack/ai-clientin any UI (headless) to manage chat state + streaming
You only need the React/Solid packages if your UI framework benefits from their hooks.
Cloudflare integration: @cloudflare/tanstack-ai
Cloudflare maintains an official integration package that makes TanStack AI work well with both:
- Workers AI (
env.AIbinding) - AI Gateway (
env.AI.gateway("<gateway-id>"))
It includes ready-to-use adapters for chat, image generation, transcription, text-to-speech, and summarization for Workers AI models, plus AI Gateway routing for OpenAI/Anthropic/Gemini/Grok/OpenRouter. See:
Install
npm install @tanstack/ai @tanstack/ai-client @cloudflare/tanstack-ai
If you want to route to third-party providers through AI Gateway, also install the TanStack provider packages you use (for example OpenAI or Anthropic):
npm install @tanstack/ai-openainpm install @tanstack/ai-anthropic
Bindings (packages/worker/wrangler.jsonc)
Add the Workers AI binding in each environment you want:
"ai": { "binding": "AI" }
Then your Worker receives env.AI at runtime.
Server-first usage (no React required)
TanStack AI supports multiple streaming formats. A common pattern is:
- A Worker endpoint accepts
{ messages, conversationId? }as JSON - Server runs
chat(...)and returns a streamingResponse - Your UI uses
@tanstack/ai-clientwith either:fetchHttpStream("/api/chat")(newline-delimited JSON), orfetchServerSentEvents("/api/chat")(SSE)
Workers AI example (direct binding, no third-party API keys):
import { createWorkersAiChat } from '@cloudflare/tanstack-ai'
import { chat, toHttpResponse } from '@tanstack/ai'
const adapter = createWorkersAiChat('@cf/meta/llama-4-scout-17b-16e-instruct', {
binding: env.AI,
})
const stream = chat({
adapter,
stream: true,
messages,
conversationId,
})
return toHttpResponse(stream)
AI Gateway example (route OpenAI requests through your gateway):
import { createOpenAiChat } from '@cloudflare/tanstack-ai'
import { chat, toHttpResponse } from '@tanstack/ai'
const adapter = createOpenAiChat('gpt-4o', {
binding: env.AI.gateway('my-gateway-id'),
// Depending on your gateway mode, you may not need to pass an API key here.
// apiKey: env.OPENAI_API_KEY,
})
const stream = chat({ adapter, stream: true, messages, conversationId })
return toHttpResponse(stream)
Client usage (headless, works with any UI toolkit) looks like:
import { ChatClient, fetchHttpStream } from '@tanstack/ai-client'
const client = new ChatClient({
connection: fetchHttpStream('/api/chat'),
onMessagesChange: (next) => {
// Render however your app renders (not tied to React)
console.log(next)
},
})