---
title: "Cloudflare Workers AI"
description: "Use GistUI with models on Cloudflare Workers AI, from a Worker with the AI SDK provider or through the OpenAI-compatible endpoint."
---

> Documentation Index
> Fetch the complete documentation index at: https://gistui.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare Workers AI

There are two ways to reach Workers AI. Inside a Worker, use the AI binding through the AI SDK provider. From anywhere else, use the OpenAI-compatible REST endpoint.

## In a Worker, with the AI SDK

```sh
npm i ai workers-ai-provider @gistui/catalog
yarn add ai workers-ai-provider @gistui/catalog
pnpm add ai workers-ai-provider @gistui/catalog
bun add ai workers-ai-provider @gistui/catalog
```

```jsonc title="wrangler.jsonc"
{
  "ai": { "binding": "AI" }
}
```

```ts title="src/index.ts"
import { prompt } from "@gistui/catalog";
import { streamText } from "ai";
import { createWorkersAI } from "workers-ai-provider";

export default {
  async fetch(req: Request, env: Env): Promise<Response> {
    const { messages } = await req.json<{ messages: { role: "user" | "assistant"; content: string }[] }>();
    const workersai = createWorkersAI({ binding: env.AI });

    const result = streamText({
      model: workersai("@cf/openai/gpt-oss-120b"),
      system: prompt().text,
      messages,
    });
    return result.toTextStreamResponse();
  },
};
```

`@gistui/catalog`, `@gistui/core` and `@gistui/server` have no Node-only dependencies, so they run in the Workers runtime as they are.

## From anywhere, with the OpenAI-compatible endpoint

```ts
import { prompt } from "@gistui/catalog";
import { textDeltas, toReadable } from "@gistui/server";

const res = await fetch(`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/ai/v1/chat/completions`, {
  method: "POST",
  headers: { Authorization: `Bearer ${CLOUDFLARE_API_TOKEN}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "@cf/openai/gpt-oss-120b",
    stream: true,
    messages: [{ role: "system", content: prompt().text }, ...messages],
  }),
});
if (!res.ok) return new Response(await res.text(), { status: res.status });
return new Response(toReadable(textDeltas(res, "openai")));
```

> **The raw binding stream is not plain text**
>
> `env.AI.run(model, { stream: true })` returns Workers AI's own event stream. Do not pass it to `<GistUI stream>` directly: use one of the two routes above, which give text.

## Render it

The browser side is the same as everywhere else: `<GistUI library={ui} stream={res.body} />`. See [Frameworks](/docs/frameworks/).

Source: https://gistui.com/docs/models/cloudflare-workers-ai/index.mdx
