@cloudflare/tanstack-ai is the community Cloudflare package. It provides:
Cloudflare maintains this package. TanStack AI also has its own Cloudflare adapter, @tanstack/ai-cloudflare. See the Cloudflare adapter page.
npm i @cloudflare/tanstack-ai @tanstack/aipnpm add @cloudflare/tanstack-ai @tanstack/aiyarn add @cloudflare/tanstack-ai @tanstack/aibun add @cloudflare/tanstack-ai @tanstack/aiInside a Cloudflare Worker, use the env.AI binding. You need no API key.
Outside a Worker, use the REST credentials. Put them in the environment of your server:
CLOUDFLARE_ACCOUNT_ID=your-account-id
CLOUDFLARE_API_KEY=your-api-keyimport { chat, toHttpResponse } from "@tanstack/ai";
import { createWorkersAiChat } from "@cloudflare/tanstack-ai";
import { env } from "./env";
const adapter = createWorkersAiChat(
"@cf/meta/llama-4-scout-17b-16e-instruct",
{ binding: env.AI },
);
const response = chat({
adapter,
stream: true,
messages: [{ role: "user", content: "Hello!" }],
threadId: "thread-1",
});
const httpResponse = toHttpResponse(response);Return httpResponse from your Worker. Outside a Worker, pass the account ID and the API key:
import { createWorkersAiChat } from "@cloudflare/tanstack-ai";
const adapter = createWorkersAiChat(
"@cf/meta/llama-4-scout-17b-16e-instruct",
{
accountId: "your-account-id",
apiKey: "your-api-key",
},
);import { generateImage } from "@tanstack/ai";
import { createWorkersAiImage } from "@cloudflare/tanstack-ai";
import { env } from "./env";
const adapter = createWorkersAiImage(
"@cf/stabilityai/stable-diffusion-xl-base-1.0",
{ binding: env.AI },
);
const result = await generateImage({
adapter,
prompt: "a cat in space",
threadId: "thread-1",
});
console.log(result.images[0]?.b64Json);import { generateTranscription } from "@tanstack/ai";
import { createWorkersAiTranscription } from "@cloudflare/tanstack-ai";
import { env, audioArrayBuffer } from "./env";
const adapter = createWorkersAiTranscription(
"@cf/openai/whisper-large-v3-turbo",
{ binding: env.AI },
);
const result = await generateTranscription({
adapter,
audio: audioArrayBuffer,
threadId: "thread-1",
});
console.log(result.text);
console.log(result.segments);Transcription models: @cf/openai/whisper, @cf/openai/whisper-tiny-en, @cf/openai/whisper-large-v3-turbo, and @cf/deepgram/nova-3.
import { generateSpeech } from "@tanstack/ai";
import { createWorkersAiTts } from "@cloudflare/tanstack-ai";
import { env } from "./env";
const adapter = createWorkersAiTts("@cf/deepgram/aura-2-en", {
binding: env.AI,
});
const result = await generateSpeech({
adapter,
text: "Hello world",
threadId: "thread-1",
});
console.log(result.audio);import { summarize, type AnySummarizeAdapter } from "@tanstack/ai";
import { createWorkersAiSummarize } from "@cloudflare/tanstack-ai";
import { env } from "./env";
const adapter: AnySummarizeAdapter = createWorkersAiSummarize("@cf/facebook/bart-large-cnn", {
binding: env.AI,
});
const result = await summarize({
adapter,
text: "Long article here...",
threadId: "thread-1",
});
console.log(result.summary);Send requests through AI Gateway to get caching, rate limits, and one bill. It works for Workers AI and for other providers.
Workers AI through the gateway:
import { createWorkersAiChat } from "@cloudflare/tanstack-ai";
import { env } from "./env";
const adapter = createWorkersAiChat(
"@cf/meta/llama-4-scout-17b-16e-instruct",
{
binding: env.AI.gateway("my-gateway-id"),
apiKey: env.WORKERS_AI_TOKEN,
},
);Other providers through the gateway. For other providers, also install their TanStack AI packages:
npm i @tanstack/ai-openai @tanstack/ai-anthropic @tanstack/ai-gemini @tanstack/ai-grok @tanstack/ai-openrouterpnpm add @tanstack/ai-openai @tanstack/ai-anthropic @tanstack/ai-gemini @tanstack/ai-grok @tanstack/ai-openrouteryarn add @tanstack/ai-openai @tanstack/ai-anthropic @tanstack/ai-gemini @tanstack/ai-grok @tanstack/ai-openrouterbun add @tanstack/ai-openai @tanstack/ai-anthropic @tanstack/ai-gemini @tanstack/ai-grok @tanstack/ai-openrouterInstall only the providers that you use. In a Worker, use the binding:
import {
createOpenAiChat,
createAnthropicChat,
createGeminiChat,
createGrokChat,
createOpenRouterChat,
} from "@cloudflare/tanstack-ai";
import { env } from "./env";
const openai = createOpenAiChat("gpt-4o", {
binding: env.AI.gateway("my-gateway-id"),
});
const anthropic = createAnthropicChat("claude-sonnet-4-5", {
binding: env.AI.gateway("my-gateway-id"),
});
const grok = createGrokChat("grok-4.3", {
binding: env.AI.gateway("my-gateway-id"),
});
const openrouter = createOpenRouterChat("openai/gpt-4o", {
binding: env.AI.gateway("my-gateway-id"),
});Outside a Worker, use the credentials:
import { createOpenAiChat } from "@cloudflare/tanstack-ai";
const adapter = createOpenAiChat("gpt-4o", {
accountId: "your-account-id",
gatewayId: "your-gateway-id",
cfApiKey: "your-cf-api-key",
apiKey: "provider-api-key",
});The binding mode and the credentials mode both take cache options:
import { createOpenAiChat } from "@cloudflare/tanstack-ai";
import { env } from "./env";
const adapter = createOpenAiChat("gpt-4o", {
binding: env.AI.gateway("my-gateway-id"),
skipCache: false,
cacheTtl: 3600,
customCacheKey: "my-key",
metadata: { user: "test" },
});Workers AI has four modes:
| Mode | Config | What it does |
|---|---|---|
| Plain binding | { binding: env.AI } | Direct access, no gateway. |
| Plain REST | { accountId, apiKey } | REST API, no gateway. |
| Gateway binding | { binding: env.AI.gateway(id) } | Through AI Gateway, with the binding. |
| Gateway REST | { accountId, gatewayId, ... } | Through AI Gateway, with REST. |
Other providers (OpenAI, Anthropic, Gemini, Grok, OpenRouter) work only in the gateway modes.
| Provider | Chat | Summarize | Images | Transcription | Speech |
|---|---|---|---|---|---|
| Workers AI | Yes | Yes | Yes | Yes | Yes |
| OpenAI | Yes | Yes | Yes | Yes | Yes |
| Anthropic | Yes | Yes | No | No | No |
| Gemini | Yes | Yes | Yes | No | Yes |
| Grok | Yes | Yes | Yes | No | No |
| OpenRouter | Yes | Yes | Yes | No | No |
The source and the issues are on GitHub.