Deployments
Cloudflare
Use the Cloudflare target when route handlers, loaders, middleware, metadata, or server-rendered pages should run on Cloudflare Workers runtime.
Build artifacts
mreact-router build --target=cloudflareThe build emits .mreact/cloudflare/worker.mjs, route modules, server route modules, and .mreact/client assets. Generated server route modules dispatch GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, and ALL exports with decoded params and context.env, so route handlers can use Worker bindings.
Cloudflare Pages advanced mode
Use Pages advanced mode when you want Cloudflare Pages to host the static assets and run the generated Worker as _worker.js. Build the Cloudflare target, package the generated worker and static assets, then deploy the packaged directory to a named Pages project.
mreact-router build --target=cloudflare
mreact-router package cloudflare-pages --from .mreact --out .mreact/pages
wrangler pages deploy .mreact/pages --project-name=mreact-app --branch=mainPages provides the ASSETS binding to _worker.js. Mreact serves only allowed manifest assets, route-linked CSS, generated client assets, and copied public files from that binding, which keeps traversal-style asset requests out of the static asset path.
Workers deployment
Use Workers when you want an ordinary Worker service with an explicit static assets binding. The generator writes wrangler.toml, and Wrangler also accepts a JSONC config when you prefer that format. Point main at the generated Worker and bind .mreact/client as ASSETS.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "mreact-app",
"main": ".mreact/cloudflare/worker.mjs",
"compatibility_date": "2026-06-11",
"assets": {
"directory": ".mreact/client",
"binding": "ASSETS",
},
}Build, smoke-test locally, then deploy.
mreact-router build --target=cloudflare
wrangler dev
wrangler deployIf your build script also generates CSS or public assets, run that script before mreact-router build. The Hacker News example does this through pnpm --filter @reckona/example-hacker-news worker:check, which builds Tailwind CSS, emits the Worker, and imports the generated Worker for a smoke test.
Choose Workers when you manage a Worker service directly or need Worker-specific routing, service bindings, custom routes, or environment separation in wrangler.jsonc. Choose Pages advanced mode when you want Pages' project workflow and a deployable directory containing _worker.js plus static assets.
Environment bindings
Cloudflare bindings are not process.env. Read them from loader, middleware, and route handler context via context.env.
import type { RouteHandlerContext } from "@reckona/mreact-router";
interface Env {
DB: D1Database;
}
export async function GET(
_request: Request,
context: RouteHandlerContext & { env: Env },
): Promise<Response> {
const result = await context.env.DB.prepare("select 1").first();
return Response.json({ result });
}Production notes
- Use
clientSourceMaps: "hidden"and upload.mreact/source-maps/client/from CI when you need Sentry symbolication. - Configure
nodejs_compatonly when your packaged Worker graph needs Cloudflare's Node.js compatibility runtime. - Keep CSP, cache headers, and host behavior explicit because Cloudflare can also add edge headers.
- Test route handlers, dynamic server-rendered pages, streaming pages, 404s, copied public files, generated route assets, and server action forms after deployment.
APP_URL=https://mreact-app.example.workers.dev
curl -fsS "$APP_URL/"
curl -fsS "$APP_URL/api/health"
curl -fsS -I "$APP_URL/robots.txt"
curl -sS -o /dev/null -w "%{http_code}\n" "$APP_URL/not-found-check"Replace /api/health and /robots.txt with routes or copied public files that your app actually provides. The not-found check should print 404.