> ## Documentation Index
> Fetch the complete documentation index at: https://better-router.bansal.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare Workers

> Deploy better-router as a Cloudflare Worker with fetch, and optional cron, queue, and email handlers.

better-router can run anywhere that speaks `fetch`. [Cloudflare Workers](https://developers.cloudflare.com/workers/) is a first-class target, not the only one.

If the project contains `wrangler.toml`, `wrangler.json`, or `wrangler.jsonc`, the plugin sets `target: "cloudflare"` automatically. You can also set it yourself:

```ts theme={null}
betterRouter({ target: "cloudflare" })
```

## What gets deployed

`vite build` emits:

| Output                 | Role                                                               |
| ---------------------- | ------------------------------------------------------------------ |
| `dist/client`          | Browser assets, SPA runtime, island hydrators                      |
| `dist/server/index.js` | Worker module with `fetch`, plus `scheduled`, `queue`, and `email` |

Wrangler should point at that server file and serve the client as [static assets](https://developers.cloudflare.com/workers/static-assets/):

```jsonc title="wrangler.jsonc" theme={null}
{
  "name": "my-app",
  "compatibility_date": "2026-09-01",
  "compatibility_flags": ["nodejs_compat"],
  "main": "./dist/server/index.js",
  "assets": {
    "directory": "./dist/client"
  }
}
```

`nodejs_compat` is required for request-scoped helpers that use `AsyncLocalStorage` (`getEnv()`, `getHonoContext()`).

## Deploy

```bash theme={null}
npx vite build
npx wrangler deploy
```

## Worker handlers

The generated module looks like this:

```ts theme={null}
export default {
  fetch,       // Hono app: pages, APIs, middleware
  scheduled,   // Cron triggers from src/worker.ts
  queue,       // Queue consumers from src/worker.ts
  email,       // Inbound Email Routing from src/worker.ts
}
```

| Handler     | Cloudflare feature                                                                      | App files                      |
| ----------- | --------------------------------------------------------------------------------------- | ------------------------------ |
| `fetch`     | HTTP requests                                                                           | `src/routes`, `src/middleware` |
| `scheduled` | [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/) | `src/worker.ts`                |
| `queue`     | [Queues](https://developers.cloudflare.com/queues/) consumer                            | `src/worker.ts`                |
| `email`     | [Email Workers](https://developers.cloudflare.com/email-routing/email-workers/)         | `src/worker.ts`                |

`fetch` is always the Hono app unless you override it in `defineWorker({ fetch })`. The other three no-op until you implement them.

See [Bindings](/bindings) for D1, KV, R2, Queues, and secrets. See [Worker entrypoint](/worker) for `defineWorker`.

## Local development

`vite dev` runs the Hono `fetch` handler. Cron, queue, and inbound email do not fire locally. Use `wrangler dev` against the production build when you need Miniflare bindings (`DB`, `KV`, `BUCKET`, queue producers):

```bash theme={null}
npx vite build
npx wrangler dev
```

Put local secrets in `.dev.vars`, not `.env`, when you use Wrangler.

## Example

[`examples/cloudflare`](https://github.com/bansal/better-router/tree/main/examples/cloudflare) is a Worker that uses all three:

| Binding          | What the example does                                                 |
| ---------------- | --------------------------------------------------------------------- |
| D1 `DB`          | Stores jobs and cron heartbeats                                       |
| Queue `JOBS`     | Form and cron enqueue work; `defineWorker({ queue })` marks jobs done |
| Cron `* * * * *` | `defineWorker({ scheduled })` writes a heartbeat and enqueues a ping  |

```bash theme={null}
pnpm --filter better-router-example-cloudflare db:migrate
pnpm --filter better-router-example-cloudflare dev:worker
```

## Node, Bun, and Deno

The same worker module is a standard `fetch` listener. Cloudflare-only bindings (D1, R2, KV, Queues) exist on `env` in production. On Node, pass `process.env` as the second argument to `worker.fetch` — see [Deployment](/deployment).
