Skip to content

Infrastructure as Effects

Infrastructure as Effects extends Infrastructure as Code by combining application code and infrastructure configuration into a single type-safe program built from Effects and Layers.

There is no separate “infra” project plus “handler” project — a Worker or Lambda Function is a Resource that ships its runtime code, with the resources it uses wired in as Bindings.

import * as Cloudflare from "alchemy/Cloudflare";
import * as Effect from "effect/Effect";
import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
import { Bucket } from "./bucket.ts";
export default Cloudflare.Worker(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
// Init — runs at deploy time (records the binding) and at cold start (builds the live client)
const bucket = yield* Cloudflare.R2.ReadWriteBucket(Bucket);
return {
// Runtime — runs per request, inside the deployed Worker
fetch: Effect.gen(function* () {
const obj = yield* bucket.get("hello.txt");
return obj
? HttpServerResponse.text(yield* obj.text())
: HttpServerResponse.text("Not found", { status: 404 });
}),
};
}).pipe(Effect.provide(Cloudflare.R2.ReadWriteBucketBinding)),
);
  • Functions & Servers — the Worker is a Resource that carries its handler; config and code deploy together.
  • Bindingsyield* Cloudflare.R2.ReadWriteBucket(Bucket) declares the capability; the provided ReadWriteBucketBinding Layer is what wires it up — here as a native Worker binding — and hands back the typed client. The binding is the SDK; there is no env.BUCKET.
  • Phases — the outer Effect runs at plantime to record bindings and again at cold start; the inner Effect runs per request.
  • Layers — resources + bindings + runtime glue package into an Effect Layer behind a typed service, so implementations swap without touching consumers.

Effect style is optional — bindings also work as plain props on an async fetch handler with a typed env via InferEnv; see Effect handlers vs async handlers.

  1. Functions & Servers — Resources that carry runtime code.
  2. Bindings — what bind() generates.
  3. Event Sources — resources that trigger your Function, as Effect Streams.
  4. Sinks — resources you write to, as Effect Sinks.
  5. APIs — schemaless RPC between your Functions and Servers, plus schema’d surfaces for trust boundaries.
  6. Phases — plantime vs runtime in depth.
  7. Layers — encapsulating infrastructure behind services.
  8. Building with Layers — build one end to end, then swap the backend.
  9. Circular Bindings — two services that reference each other.
  10. Custom Runtime — bring the model to a new compute target.