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:
- compile route handlers at start time
- compile route handlers at build time
Compile at start time
Section titled “Compile at start time”The easiest way to get started is to compile them at start time.
- add
compilebefore exporting the app:
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.
Compile at build time
Section titled “Compile at build time”- Use Wrangler to set up your project:
wrangler init elysia-on-cloudflarebun add elysia@rcbun add -d esbuild- Define your Elysia app and export Elysia instance and Worker fetch handler:
import { Elysia } from 'elysia'
// export here for AOTexport const app = new Elysia() .get('/', () => 'Hello Cloudflare Worker!')
export default { fetch: (request: Request) => app.handle(request)}- Compile Elysia’s handlers for
workerdduring your build:
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' })]})- Point Wrangler at the generated bundle. Choose either JSONC or TOML:
{ "$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" }}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.
- Start the development server:
wrangler devThis 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:
pnpm add typebox exact-mirror openapi-typesLimitations
Section titled “Limitations”Here are some known limitations of using Elysia on Cloudflare Workers:
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.- Generate OpenAPI types during your build. A Worker cannot inspect TypeScript source files that are not included in its bundle.
- Avoid plugins that construct runtime-only objects during build or module initialization. Workers restrict some operations outside request handling.
- 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')Static files
Section titled “Static files”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:
{ "$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" }}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:
Bindings
Section titled “Bindings”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.
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.
AoT compilation
Section titled “AoT compilation”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.