Skip to content

Overview

The cf adapter, WorkerExportedHandle, and Workers-specific constraints.

AI generated, pending review Updated 10 days ago · Flare 0.3

Cloudflare Workers run the same Flare graph as Node with the cf adapter. host.build() returns an app whose export() method produces a WorkerExportedHandle: a { fetch } object you assign to export default.

import { FlareHost, FlareResponse } from "@flare-ts/core";
import { cf } from "@flare-ts/core/cloudflare";
const host = new FlareHost(cf);
host.http.get("/health", () => new FlareResponse(200, { ok: true }));
const app = host.build();
export default app.export();

The runtime calls fetch(request, env, ctx) on every request. The same controllers, services, contracts, and middleware that run on Node run here; only the entrypoint differs.

TopicRule
Singletonshost.singleton() does not exist on a Cloudflare host. Use host.scoped() per request.
Config fileNo runtime flare.json read. Bundle config with buildCf(flareJson), or pass an env record as buildCf(flareJson, env).
nodejs_compatRequired (Flare uses AsyncLocalStorage for logging).
Front-door WebSocket channelsNot available (sockets are request-scoped). Use a Durable Object for shared broadcast.
Durable ObjectsRegister with host.durableObject(Class) and handle.mount(path).

host.singleton does not exist on a Cloudflare host. The cf adapter stamps only the durableObject extension, so referencing host.singleton is a TypeScript error, not a special argument type or a runtime throw. Register per-request services with host.scoped().

That absence is doing real work. Ported by hand, module-scope state does not error on Workers; it forks: one copy per isolate, reset whenever the platform recycles one, so a hand-carried counter or cache disagrees with itself under load, and nothing surfaces the problem before production traffic does. The config file read at boot has no filesystem to read from either. The adapter turns both differences into things you hit before deploy: process-lifetime registration is absent from the host’s type, and config arrives through buildCf at build() instead of a runtime file read.

When you want flare.json values baked into the worker bundle:

import { FlareHost, FlareResponse } from "@flare-ts/core";
import { buildCf } from "@flare-ts/core/cloudflare";
import flareJson from "./flare.json" with { type: "json" };
const host = new FlareHost(buildCf(flareJson));
host.http.get("/health", () => new FlareResponse(200, { ok: true }));
const app = host.build();
export default app.export();

To layer FLARE__* values over the bundled config, pass an env record as buildCf(flareJson, env); the merge runs once at build(), not per request. Wrangler [vars] land on the runtime Worker env and are read through Bindings, never as Flare config.