Cloudflare Workers
Run effect-auth on the Cloudflare Workers runtime.
Cloudflare Workers run ES modules in V8 isolates and expose web-standard Request, Response, streams, and Web Crypto APIs. An Effect Auth deployment has three distinct parts:
request -> Worker fetch -> Effect web handler -> auth services
|-> D1 binding (persistent auth records)
|-> Durable Object binding (rate-limit coordination)
`-> Send Email binding (delivery)
deployment tool (Wrangler or Alchemy) -> creates and binds those resources| Concern | Owner |
|---|---|
HTTP entrypoint, env, isolate lifecycle | Cloudflare Workers runtime |
| Tables, migrations, queries | D1 plus an Effect Auth storage adapter |
| Resource creation and deployment | Wrangler, Alchemy, or another infrastructure tool |
Alchemy is therefore optional infrastructure, not part of the runtime adapter. See Alchemy infrastructure for its resource declarations and D1 storage for database setup. The Quick Start combines all three concerns into one deployable application.
Worker entrypoint
Cloudflare's current module Worker syntax exports an object with fetch(request, env, ctx). Bindings arrive on env; declare their types explicitly and pass them into the app-owned Effect layer factory:
import { HttpRouter } from "effect/unstable/http";
interface Env {
readonly DB: D1Database;
readonly RATE_LIMITER: DurableObjectNamespace;
readonly AUTH_EMAIL: { send(message: unknown): Promise<unknown> };
readonly AUTH_SECRET: string;
readonly AUTH_ALLOWED_ORIGINS: string;
}
export default {
fetch(request: Request, env: Env): Promise<Response> {
const webHandler = HttpRouter.toWebHandler(makeAuthLayer(env), {
disableLogger: true,
});
return webHandler.handler(request);
},
} satisfies ExportedHandler<Env>;makeAuthLayer is the composition shown in the Quick Start: it supplies D1EffectQbSqliteAuthStorageLive(env.DB), WebCryptoLive(), the mail binding, the Durable Object rate-limit store, secrets, selected features, and HttpServer.layerServices. The current Effect API returns an object from HttpRouter.toWebHandler; call .handler(request), not the object itself.
The example constructs the handler per request, which guarantees that changed bindings and secrets are observed. Cloudflare may reuse an isolate for concurrent and later requests, but may evict it at any time; mutable global memory is neither durable nor globally shared. A handler may be cached only as an optimization when its captured env remains valid. The repository's TanStack example caches a handler because it imports a stable runtime env; a raw Worker should prefer the straightforward per-request form unless profiling justifies an env-aware cache. Never use handler memory for sessions, rate limits, or locks.
Bindings and compatibility
Bindings are capability-bearing APIs, not ordinary credentials. Typical Effect Auth bindings are:
DB: a D1 binding consumed by the selected SQLite storage layer. Apply the migrations for the features you enable; D1 is persistence, not the Worker runtime itself.RATE_LIMITER: a Durable Object namespace. The adapter selects object instances by rate-limit key, providing coordination that isolate-local maps cannot provide. The exported class and its migration/resource declaration remain app-owned.AUTH_EMAIL: asend_emailbinding. The repo currently usesCloudflareMailer.layerwith the supported legacyEmailMessageAPI; Cloudflare's current Workers email API also documents a structured message builder for new integrations.- Secrets and text configuration:
AUTH_SECRET, public URL, cookie policy, and the exact allowed-origin list. Store secrets as Cloudflare secrets rather than plaintext configuration.
The examples enable nodejs_compat. Cloudflare documents that this flag, with a compatibility date of at least 2024-09-23, enables supported Node APIs and injected shims. Shims do not make every Node method functional, so keep runtime code on web APIs where possible. Effect Auth uses WebCryptoLive() over the Worker's global crypto; Cloudflare documents the Web Crypto surface separately from Node crypto.
Origins and lifecycle
Set AuthHttpApiConfigLive({ originCheck: { allowedOrigins } }) from an explicit allowlist. This server-side origin check protects state-changing auth requests; it is not a replacement for browser CORS response and preflight headers. If the browser calls auth cross-origin, configure both deliberately, return the requesting allowed origin rather than * when credentials are used, and include Vary: Origin.
Authentication work required for the response, including persistence and sending a requested auth email, should be awaited by the Effect handler. Use ctx.waitUntil only for non-critical post-response work such as cache writes; queues are a better fit for work requiring reliable retries.
Finally, design against the current Workers limits: CPU, memory, subrequests, bundle size, and startup limits vary by plan. Waiting on D1 or network I/O is not CPU time, but expensive global initialization counts toward startup. These APIs and links were checked against the current Cloudflare documentation; pin a compatibility date and review its changes when upgrading.