---
name: netlify-ai-gateway
description: Use Netlify AI Gateway for AI inference in Netlify Functions and server-side code. Use when adding AI/LLM features with OpenAI, Anthropic, or Google Gemini without managing API keys. Must be read before selecting or changing any AI model. Contains the list of supported models.
---

# Netlify AI Gateway

> **IMPORTANT:** Only use models listed in the "Available Models" section below. AI Gateway does not support every model a provider offers. Using an unsupported model will cause runtime errors.

Zero-config AI inference for Netlify projects. Netlify automatically injects environment variables so official
provider SDKs work without API keys or configuration.

## How It Works

Netlify sets provider-specific environment variables in all compute contexts (Functions, Edge Functions, server-side
framework code). Official SDKs auto-detect these variables, so a default constructor like `new OpenAI()` works
out of the box. Requests are proxied through AI Gateway and billed to your Netlify account credits.

Netlify **never overrides** environment variables you have already set. The check is per-provider: if you set your own
`OPENAI_API_KEY`, Netlify will not set `OPENAI_API_KEY` or `OPENAI_BASE_URL`, but will still inject Anthropic and
Gemini variables independently.

AI Gateway requires a **credit-based plan** (Free, Personal, or Pro). It is not available on legacy pricing plans.

### Environment Variables

| Provider | Variables |
|----------|-----------|
| **Anthropic** | `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL` |
| **OpenAI** | `OPENAI_API_KEY`, `OPENAI_BASE_URL` |
| **Google Gemini** | `GEMINI_API_KEY`, `GOOGLE_GEMINI_BASE_URL` |
| **Gateway (always set)** | `NETLIFY_AI_GATEWAY_KEY`, `NETLIFY_AI_GATEWAY_BASE_URL` |

## Quick Start

Install the SDK for your provider and use a zero-config constructor. No API key or base URL needed.

### Anthropic

```bash
npm install @anthropic-ai/sdk
```

```typescript
import Anthropic from '@anthropic-ai/sdk'

const anthropic = new Anthropic()

const message = await anthropic.messages.create({
  model: 'claude-opus-4-8',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello!' }],
})

console.log(message.content[0].text)
```

### OpenAI

```bash
npm install openai
```

```typescript
import OpenAI from 'openai'

const openai = new OpenAI()

const completion = await openai.chat.completions.create({
  model: 'gpt-5.2',
  messages: [{ role: 'user', content: 'Hello!' }],
})

console.log(completion.choices[0].message.content)
```

OpenAI also supports the newer Responses API:

```typescript
import OpenAI from 'openai'

const openai = new OpenAI()

const response = await openai.responses.create({
  model: 'gpt-5.2',
  input: [{ role: 'user', content: 'Hello!' }],
})

console.log(response.output_text)
```

### Gemini

```bash
npm install @google/genai
```

```typescript
import { GoogleGenAI } from '@google/genai'

const ai = new GoogleGenAI({})

const response = await ai.models.generateContent({
  model: 'gemini-3-flash-preview',
  contents: 'Hello!',
})

console.log(response.text)
```

## Streaming

### Anthropic Streaming

```typescript
import Anthropic from '@anthropic-ai/sdk'

const anthropic = new Anthropic()

const stream = await anthropic.messages.create({
  model: 'claude-opus-4-8',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Tell me a story.' }],
  stream: true,
})

for await (const event of stream) {
  if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
    process.stdout.write(event.delta.text)
  }
}
```

### OpenAI Streaming

```typescript
import OpenAI from 'openai'

const openai = new OpenAI()

const stream = await openai.chat.completions.create({
  model: 'gpt-5.2',
  messages: [{ role: 'user', content: 'Tell me a story.' }],
  stream: true,
})

for await (const chunk of stream) {
  if (chunk.choices[0]?.delta?.content) {
    process.stdout.write(chunk.choices[0].delta.content)
  }
}
```

### Gemini Streaming

```typescript
import { GoogleGenAI } from '@google/genai'

const ai = new GoogleGenAI({})

const stream = await ai.models.generateContentStream({
  model: 'gemini-3-flash-preview',
  contents: 'Tell me a story.',
})

for await (const chunk of stream) {
  if (chunk.text) {
    process.stdout.write(chunk.text)
  }
}
```

## Image Generation

### OpenAI (gpt-image-1)

```typescript
import OpenAI from 'openai'

const openai = new OpenAI()

const result = await openai.images.generate({
  model: 'gpt-image-1',
  prompt: 'A cute otter in a river',
})

const imageBase64 = result.data[0].b64_json
```

Image generation is also available via the Responses API with the `image_generation` tool:

```typescript
const response = await openai.responses.create({
  model: 'gpt-4o',
  input: 'Create a simple logo',
  tools: [{ type: 'image_generation' }],
})

for (const item of response.output) {
  if (item.type === 'image_generation_call') {
    const imageBase64 = item.result.data
  }
}
```

## Netlify Functions

Full example of a Netlify Function using AI Gateway:

```typescript
// netlify/functions/chat.mts
import type { Context } from '@netlify/functions'
import Anthropic from '@anthropic-ai/sdk'

const anthropic = new Anthropic()

export default async (req: Request, context: Context) => {
  const { prompt } = await req.json()

  const message = await anthropic.messages.create({
    model: 'claude-opus-4-8',
    max_tokens: 1024,
    messages: [{ role: 'user', content: prompt }],
  })

  return Response.json({ response: message.content[0].text })
}

export const config = {
  path: '/api/chat',
}
```

For streaming responses from a function:

```typescript
// netlify/functions/stream.mts
import type { Context } from '@netlify/functions'
import OpenAI from 'openai'

const openai = new OpenAI()

export default async (req: Request, context: Context) => {
  const { prompt } = await req.json()

  const stream = await openai.chat.completions.create({
    model: 'gpt-5.2',
    messages: [{ role: 'user', content: prompt }],
    stream: true,
  })

  return new Response(
    new ReadableStream({
      async start(controller) {
        for await (const chunk of stream) {
          const text = chunk.choices[0]?.delta?.content
          if (text) {
            controller.enqueue(new TextEncoder().encode(text))
          }
        }
        controller.close()
      },
    }),
    { headers: { 'Content-Type': 'text/plain; charset=utf-8' } },
  )
}

export const config = {
  path: '/api/stream',
}
```

## Framework Server-Side Code

AI Gateway env vars are available in any server-side context, not just Netlify Functions.

### Next.js Route Handler

```typescript
// app/api/chat/route.ts
import OpenAI from 'openai'

const openai = new OpenAI()

export async function POST(request: Request) {
  const { prompt } = await request.json()

  const completion = await openai.chat.completions.create({
    model: 'gpt-5.2',
    messages: [{ role: 'user', content: prompt }],
  })

  return Response.json({ response: completion.choices[0].message.content })
}
```

This also works in server components, API routes in Astro, Remix loaders/actions, and SvelteKit server routes.

## REST API / Direct Fetch

For HTTP-level control, use the gateway variables directly:

```typescript
const response = await fetch(`${process.env.NETLIFY_AI_GATEWAY_BASE_URL}/anthropic/v1/messages`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.NETLIFY_AI_GATEWAY_KEY}`,
    'anthropic-version': '2023-06-01',
  },
  body: JSON.stringify({
    model: 'claude-opus-4-8',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Hello!' }],
  }),
})

const data = await response.json()
```

Or using the provider-specific variables with `fetch`:

```typescript
const response = await fetch(`${process.env.ANTHROPIC_BASE_URL}/v1/messages`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': process.env.ANTHROPIC_API_KEY,
    'anthropic-version': '2023-06-01',
  },
  body: JSON.stringify({
    model: 'claude-opus-4-8',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Hello!' }],
  }),
})
```

## Available Models

For the latest list, see https://docs.netlify.com/build/ai-gateway/overview/.

<!-- AVAILABLE_MODELS -->

## Rate Limits

Tokens per minute (TPM) are scoped per **account** across all projects. For current limits per model and plan tier, see https://docs.netlify.com/build/ai-gateway/overview/.

## Limitations

- **Context window:** Max 200k tokens per request
- **Batch inference:** Not supported
- **Custom headers:** Cannot send custom request headers to providers
- **Prompt caching:** Anthropic supports 5-minute ephemeral caching only. Gemini caching is not supported. OpenAI sets `prompt_cache_key` per-account automatically.
- **Priority processing (OpenAI):** Not supported
- **Production deploy required:** At least one production deploy must exist before AI Gateway activates

## Disabling AI Gateway

To prevent Netlify from injecting any AI-related environment variables, disable AI features in the Netlify UI under
**Project configuration > Build & deploy > Build with AI > Manage AI features**.

## Monitoring Usage

View AI Gateway token usage and costs in the Netlify UI under **Team settings > Billing > Usage**. Each request's
token consumption is tracked per model and converted to Netlify credits.

## Common Errors & Solutions

### "API key not found" or env var is undefined

**Cause:** AI Gateway env vars are not injected.

**Fix:**

1. Ensure the site has at least one production deploy
2. Deploy to Netlify
3. Check that you are reading the env var in server-side code, not client-side browser code

### Rate limit exceeded (429)

**Cause:** Account hit the tokens-per-minute limit for that model.

**Fix:**

1. Wait briefly and retry — TPM limits reset each minute
2. Switch to a smaller/cheaper model (e.g. `gpt-4.1-mini` instead of `gpt-4.1`)
3. Reduce prompt length or `max_tokens`
4. Upgrade plan tier for higher limits

### Model not available

**Cause:** The requested model is not supported through AI Gateway.

**Fix:**

1. Check the available models list above
2. Use the exact model ID string (e.g. `claude-sonnet-4-5-20250929`, not `claude-sonnet`)

## Packages

```bash
# Anthropic
npm install @anthropic-ai/sdk

# OpenAI
npm install openai

# Google Gemini
npm install @google/genai
```
