Skip to content

Cloudflare Worker

Elysia can run on Cloudflare Workers using Web Standard requests and responses.

For Elysia v2, there’s no need for Cloudflare adapter. You can either:

  1. compile route handlers at start time
  2. compile route handlers at build time

The easiest way to get started is to compile them at start time.

  1. add compile before exporting the app:
src/index.ts
import { Elysia } from 'elysia'
const app = new Elysia()
.get('/', () => 'Hello Cloudflare Worker!')
.compile()
export default {
fetch: (request: Request) => app.handle(request)
}

However, there’s an overhead of compiling the handlers at start time, which can be avoided by compiling them at build time.

  1. Use Wrangler to set up your project:
Terminal window
wrangler init elysia-on-cloudflare
bun add elysia@rc
bun add -d esbuild
  1. Define your Elysia app and export Elysia instance and Worker fetch handler:
src/index.ts
import { Elysia } from 'elysia'
// export here for AOT
export const app = new Elysia()
.get('/', () => 'Hello Cloudflare Worker!')
export default {
fetch: (request: Request) => app.handle(request)
}
  1. Compile Elysia’s handlers for workerd during your build:
build.ts
import * as esbuild from 'esbuild'
import { aot } from 'elysia/plugin/aot/esbuild'
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
format: 'esm',
outfile: 'dist/worker.js',
conditions: ['workerd', 'worker', 'browser', 'import'],
platform: 'browser',
target: 'esnext',
external: ['node:*', 'cloudflare:*'],
plugins: [aot('src/index.ts', { target: 'workerd' })]
})
  1. Point Wrangler at the generated bundle. Choose either JSONC or TOML:
wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "elysia-on-cloudflare",
"main": "dist/worker.js",
"compatibility_date": "2025-09-06",
"compatibility_flags": ["nodejs_compat"],
"build": { "command": "bun build.ts" }
}
wrangler.toml
name = "elysia-on-cloudflare"
main = "dist/worker.js"
compatibility_date = "2025-09-06"
compatibility_flags = ["nodejs_compat"]
[build]
command = "bun build.ts"

The compatibility date and nodejs_compat flag match Elysia’s v2 Cloudflare fixture. Keep the flag for this setup; the v1 advice to omit it does not apply here.

  1. Start the development server:
Terminal window
wrangler dev

This starts the local Worker at http://localhost:8787. To deploy it, run wrangler deploy.

If your pnpm configuration does not install peer dependencies, add the peers required by Elysia v2 explicitly:

Terminal window
pnpm add typebox exact-mirror openapi-types

Here are some known limitations of using Elysia on Cloudflare Workers:

  1. file() and the Static plugin must not assume access to your development machine’s filesystem. Workers provide a virtual filesystem, including with the compatibility settings above; use static assets for files you want to publish.
  2. Generate OpenAPI types during your build. A Worker cannot inspect TypeScript source files that are not included in its bundle.
  3. Avoid plugins that construct runtime-only objects during build or module initialization. Workers restrict some operations outside request handling.
  4. Use a function handler when returning a value, so response creation happens while handling a request:
import { Elysia } from 'elysia'
new Elysia()
.get('/', () => 'Hello Elysia')

Use Cloudflare’s built-in static file serving to publish your public directory without relying on a filesystem-based static plugin.

Add the following to your wrangler config:

wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "elysia-on-cloudflare",
"main": "dist/worker.js",
"compatibility_date": "2025-09-06",
"compatibility_flags": ["nodejs_compat"],
"build": { "command": "bun build.ts" },
"assets": { "directory": "public" }
}
wrangler.toml
name = "elysia-on-cloudflare"
main = "dist/worker.js"
compatibility_date = "2025-09-06"
compatibility_flags = ["nodejs_compat"]
assets = { directory = "public" }
[build]
command = "bun build.ts"

Create a public folder and place your static files in it.

For example, if you have a folder structure like this:

Then you should be able to access your static files from the following paths:

You can use Cloudflare Workers bindings by importing env from cloudflare:workers. Import it inside the handler so the build process does not need to resolve a Worker-only module.

src/index.ts
import { Elysia } from 'elysia'
export const app = new Elysia()
.get('/', async () => {
const { env } = await import('cloudflare:workers')
return `Hello ${await env.KV.get('my-key')}`
})
export default {
fetch: (request: Request) => app.handle(request)
}

Configure a KV binding in Wrangler and generate its TypeScript types with wrangler types. The external cloudflare:* imports stay available to the Worker runtime.

See Cloudflare Workers: Bindings for more information about bindings.

In v1, Workers originally required aot: false. Cloudflare later added Function compilation during startup, and Elysia 1.4.7’s Cloudflare adapter used it with a compatibility date of at least 2025-06-01.

Elysia v2 uses a different compilation pipeline. The aot build plugin above moves handler generation into the build, using target: 'workerd' to generate code for Workers even when the build runs on Bun.

Calling .compile() warms up Elysia’s handlers in the current runtime. It does not replace the Worker build step, and v2 has no aot: false constructor option.

import { Elysia } from 'elysia'
const app = new Elysia()
.get('/', () => 'Hello Elysia')
.compile()

The deployment and binding examples still need to be tested against your Cloudflare account and chosen dependency versions.

Type to search the documentation.

    Up arrowDown arrow to navigateEnter to selectEscape to close