---
title: "Cloudflare Deployment"
description: "Deploy Nuxt OG Image to Cloudflare Workers or Pages."
canonical_url: "https://nuxtseo.com/docs/og-image/guides/cloudflare"
last_updated: "2026-05-06T18:45:03.801Z"
---

Nuxt OG Image works on Cloudflare Workers and Pages with the [Takumi](/docs/og-image/renderers/takumi) (recommended) or [Satori](/docs/og-image/renderers/satori) renderer using Wasm bindings.

## Static Assets (ASSETS Binding)

OG image generation requires loading font files at runtime. On [Cloudflare](https://cloudflare.com), fonts are served as static assets through the [`ASSETS` binding](https://developers.cloudflare.com/workers/static-assets/binding/). Without this binding, the worker cannot access fonts and all text will be invisible.

### Cloudflare Pages

No extra configuration needed. The `wrangler pages deploy` command configures the `ASSETS` binding automatically.

### Cloudflare Workers (Module)

Enable `deployConfig` so Nitro generates a `wrangler.json` with the `ASSETS` binding:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-module',
    cloudflare: {
      deployConfig: true,
    },
  },
})
```

Then build and deploy:

```bash
nuxt build
npx wrangler --cwd .output deploy
```

<warning>

Do **not** deploy with `wrangler deploy --assets .output/public`. This legacy command does not configure the `ASSETS` binding. Use `npx wrangler --cwd .output deploy` which reads the generated `wrangler.json`.

</warning>

You can verify the binding exists in the deploy output:

```text
Your Worker has access to the following bindings:
Binding            Resource
env.ASSETS         Assets
```

### Custom Wrangler Config

If you manage your own `wrangler.toml`, add the `[assets]` section:

```toml [wrangler.toml]
[assets]
binding = "ASSETS"
directory = ".output/public"
```

## Runtime Cache with KV

The module caches rendered OG images in memory by default, which resets on every deploy. For persistent caching, use [Cloudflare KV](https://developers.cloudflare.com/kv/).

### 1. Create a KV Namespace

```bash
npx wrangler kv namespace create OG_IMAGE_CACHE
```

### 2. Add the Binding

<code-group>

```toml [wrangler.toml]
[[kv_namespaces]]
binding = "OG_IMAGE_CACHE"
id = "<your-namespace-id>"
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  nitro: {
    cloudflare: {
      wrangler: {
        kv_namespaces: [
          { binding: 'OG_IMAGE_CACHE', id: '<your-namespace-id>' },
        ],
      },
    },
  },
})
```

</code-group>

### 3. Configure Cache Storage

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    runtimeCacheStorage: {
      driver: 'cloudflare-kv-binding',
      binding: 'OG_IMAGE_CACHE',
    },
  },
})
```

See the [Runtime Cache guide](/docs/og-image/guides/runtime-cache) for more caching options.

## Browser Rendering

[Cloudflare Browser Rendering](https://developers.cloudflare.com/browser-rendering/) enables runtime screenshots for `.browser.vue` templates. This is not needed for Takumi or Satori templates.

### 1. Install the Dependency

```bash
pnpm add @cloudflare/puppeteer
```

### 2. Add the Binding

<code-group>

```toml [wrangler.toml]
[browser]
binding = "BROWSER"
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    browser: {
      provider: 'cloudflare',
      binding: 'BROWSER',
    },
  },
})
```

</code-group>

### Rate Limits

<table>
<thead>
  <tr>
    <th>
      Plan
    </th>
    
    <th>
      New browsers per minute
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Free
    </td>
    
    <td>
      3
    </td>
  </tr>
  
  <tr>
    <td>
      Paid
    </td>
    
    <td>
      30
    </td>
  </tr>
</tbody>
</table>

Sessions have a 60 second idle timeout, handled automatically by the module. See [Cloudflare Browser Rendering limits](https://developers.cloudflare.com/browser-rendering/limits/) for details.

## Troubleshooting

### Text missing from OG images

If the background and images render but text is invisible, the `ASSETS` binding is missing. Verify your deployment follows the [setup above](#static-assets-assets-binding).

To diagnose, enable `ogImage.debug` and check the `.json` variant of your OG image URL. If `fonts` is an empty array, fonts failed to load.

### Fonts load locally but not in production

`wrangler dev` injects the `ASSETS` binding automatically, so fonts work in local preview. Production deployments need the binding configured explicitly via `deployConfig: true` or a `wrangler.toml` with `[assets]`.
