mion can run on Cloudflare Workers for globally-distributed edge deployments. The @mionjs/platform-cloudflare package provides a Web standard Request -> Response fetch handler with access to Worker bindings via the platform context.
npm install @mionjs/platform-cloudflare @mionjs/router
import {initMionRouter} from '@mionjs/router';
import {createCloudflareHandler} from '@mionjs/platform-cloudflare';
import {routes} from './cloudflare-routes.ts';
await initMionRouter(routes, {aot: true});
export default createCloudflareHandler();
import {Routes, route} from '@mionjs/router';
export const routes = {
sayHello: route((ctx, name: string): string => {
return `Hello ${name}!`;
}),
} satisfies Routes;
A minimal wrangler.toml for a mion Worker:
name = "my-mion-api"
main = "dist/worker.js"
compatibility_date = "2024-01-01"
The main field points to the bundled output produced by Vite (see AOT Compilation Required below). Run wrangler deploy to publish.
You can pass configuration options to createCloudflareHandler:
import {initMionRouter} from '@mionjs/router';
import {createCloudflareHandler} from '@mionjs/platform-cloudflare';
import {routes} from './cloudflare-routes.ts';
await initMionRouter(routes, {aot: true, basePath: 'api'});
export default createCloudflareHandler({
basePath: '/api',
defaultResponseHeaders: {'access-control-allow-origin': '*'},
});
env (your Worker bindings — KV, D1, R2, secrets, etc.) and ctx (the Worker ExecutionContext with waitUntil/passThroughOnException) on the mion call context's platform context. This is the canonical way to access Worker bindings from your route handlers.new Function() or eval(). You must enable mion's AOT compilation in your Vite build, otherwise the router will throw AOTCacheError when it tries to register routes inside the Worker.mion's default JIT compilation generates validation and serialization functions at runtime using new Function(). Workers block this for security reasons, so Cloudflare projects must be bundled with pre-compiled AOT caches. The mion Vite plugin handles this automatically — see AOT Compilation for the full explanation.
A minimal vite.config.ts for a Cloudflare Worker:
import {defineConfig} from 'vite';
import {mionPlugin} from '@mionjs/devtools/vite-plugin';
export default defineConfig({
plugins: [
mionPlugin({
aotCaches: {},
server: {
startScript: 'src/index.ts',
runMode: 'buildOnly',
},
}),
],
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: 'worker',
},
rollupOptions: {
output: {inlineDynamicImports: true},
},
},
});
inlineDynamicImports: true is required because Workers don't support dynamic code splitting — every dependency must be bundled into a single file.
The Worker entry file calls initMionRouter with aot: true to enable strict AOT mode. In strict mode @mionjs/run-types is not loaded at all, every route must be present in the AOT cache, and the Vite plugin auto-injects the cache contents at bundle time:
import {initMionRouter} from '@mionjs/router';
import {createCloudflareHandler} from '@mionjs/platform-cloudflare';
import {routes} from './cloudflare-routes.ts';
await initMionRouter(routes, {aot: true});
export default createCloudflareHandler();
virtual:mion-aot/caches or call addAOTCaches() manually — when the plugin's aotCaches option is set, the Vite plugin auto-wires everything. For a deeper explanation of how this works see AOT Compilation and Vite Configuration.For TypeScript support of the virtual modules (only needed if you import them manually), add this to your tsconfig.json:
{
"compilerOptions": {
"types": ["@mionjs/devtools/virtual-modules"]
}
}
export interface CloudflareHandlerOptions {
/** Set of default response headers to add to every response */
defaultResponseHeaders: Record<string, string>;
/** Path prefix to strip from incoming URL (e.g., '/api/mion') */
basePath: string;
}