Platforms

Cloudflare Workers

Running mion APIs on Cloudflare Workers using the Web standard fetch handler.

@mionjs/platform-cloudflare provides a Web standard Request -> Response fetch handler with access to Worker bindings.

Installing the Adapter

npm install @mionjs/platform-cloudflare @mionjs/router

Creating the Handler

import {createCloudflareHandler} from '@mionjs/platform-cloudflare';
import './cloudflare-routes.ts';

export default createCloudflareHandler();

Cloudflare Configuration

A minimal wrangler.toml for a mion Worker, where main points to the Vite bundle. Run wrangler deploy to publish.

name = "my-mion-api"
main = "dist/worker.js"
compatibility_date = "2024-01-01"

Handler Options

Pass options such as maxBodySize (128 KB by default) and maxBodySizeCap to createCloudflareHandler. maxBodySizeCap defaults to the 100 MB Cloudflare allows on the Free and Pro plans; override it on Business or Enterprise, which allow more. The handler's basePath strips a URL prefix before routing. Router options, including the router's own basePath, go in createMionRouter. Each route has its own body limit, and a streamed body is cancelled with a 413 the moment it passes it.

import {createCloudflareHandler} from '@mionjs/platform-cloudflare';
import './cloudflare-routes.ts';

export default createCloudflareHandler({
  basePath: '/api',
  maxBodySize: 512 * 1024,
});
The handler puts env (your Worker bindings: KV, D1, R2, secrets, etc.) and ctx (the Worker ExecutionContext with waitUntil/passThroughOnException) on the call context's platform context. Use it to read Worker bindings in your route handlers.

Vite Configuration

A minimal vite.config.ts for a Worker. The Worker entry needs no special setup beyond Creating the Handler.

Cloudflare Workers do not allow new Function() or eval(), so a Worker build must set runTypes: {emitMode: 'both'} on the mion Vite plugin.The default emitMode: 'code' ships each build-time compiled function as a source string that new Function turns into a real function on first use, and mion.initRoutes fails on the first route with "Code generation from strings disallowed for this context". 'both' also ships the live function, so nothing is compiled at runtime or at cold start. The cost: roughly +30% raw bundle size, +15% gzipped.
vite.config.ts
import {defineConfig} from 'vite';
import {resolve} from 'path';
import {mionVitePlugin} from '@mionjs/devtools/vite';

export default defineConfig({
  plugins: [
    mionVitePlugin({
      tsConfig: resolve(__dirname, 'tsconfig.json'),
      runTypes: {
        // required on Workers: no `new Function` at runtime
        emitMode: 'both',
      },
    }),
  ],
  build: {
    lib: {
      entry: 'src/index.ts',
      formats: ['es'],
      fileName: 'worker',
    },
    rollupOptions: {
      // Workers do not support dynamic code splitting, so bundle everything into one file
      output: {inlineDynamicImports: true},
    },
  },
});

Cloudflare Databases

Cloudflare's two SQLite databases, D1 and Durable Objects storage, both work with the SQLite table package. Declare the table once and pick the driver where you connect, see Cloudflare D1 and Durable Objects.

Copyright © 2026