The tightest feedback loop from edit to production

Cloud programs composed from Layers: type-checked, emulated locally, tested live, and deployed per pull request.

Every step is optimized

Iterate on your machine and then let CI deploy a preview, test it, and ship it on merge. The type checker answers in milliseconds, emulated tests in seconds, and the real cloud in about 20 seconds.

See the example app and benchmark on GitHub

StagedThe agent's typing is staged. The type check itself answers in milliseconds.
my-app — src/api.ts
1export default Cloudflare.Worker(
2 "Api",
3 { main: import.meta.url },
4 Effect.gen(function* () {
5 return {
6 fetch: Effect.gen(function* () {
7 const request = yield* HttpServerRequest;
8 return HttpServerResponse.empty({ status: 201 });
9 }),
10 };
11 }),
12);
agent · my-appTYPE-CHECK
›

Your machine · edit

Infrastructure is part of your application

Other IaC tools split an app into two programs, but every feature you build crosses that line. In Alchemy, a Layer owns its infrastructure and service implementation so that features can be decomposed.

PHOTOS MODULE
  1. InfrastructurePhotos bucket
  2. Configuration & policiesread/write binding
  3. APIs & business logicupload()
  4. Frontendupload button
runtime programinfrastructure program
src/Photos.ts
export class Photos extends Context.Service<Photos, {
  upload(name: string, body: string): Effect.Effect<void>;
}>()("Photos") {}

export const PhotosR2 = Layer.effect(
  Photos,
  Effect.gen(function* () {
    // resource
    const bucket = yield* Cloudflare.R2.Bucket("Photos");
    // binding: read/write access for this Worker only
    const photos = yield* Cloudflare.R2.ReadWriteBucket(bucket);
    // API
    return {
      upload: (name, body) => photos.put(name, body),
    };
  }),
);

Your machine · type-check

Type checking proves your infra is correct

Each Layer declares what it needs in its type: the resources it creates, the access it grants, and the services it calls. Leave one out and the program doesn't compile, so a broken stack fails in your editor in milliseconds, before anything deploys.

Your machine · test, emulated

Get fast feedback with local emulation

alchemy dev runs Workers, Durable Objects, queues and buckets on emulated services on your machine, and the frontend reloads as you type. Set dev: true in a test and the same suite runs against those services in seconds, with nothing deployed.

alchemy.run.ts
import Api from "./src/api.ts";

export default Alchemy.Stack(
  "my-app",
  { providers: Cloudflare.providers() },
  Effect.gen(function* () {
    // backend: a Cloudflare Worker, run locally in workerd
    const api = yield* Api;
    // frontend: a Vite app that calls it
    const web = yield* Cloudflare.Website.Vite("Web", {
      env: { VITE_API_URL: api.url },
    });
    return { web: web.url, api: api.url };
  }),
);
~/my-appDEV

Your machine · test, live

Test a live deployment when ready to PR

Once it works locally, run the same test without LOCAL=1. It deploys the app to a stage of its own, runs against real Workers, buckets and permissions, and destroys the stage afterwards, in about 20 seconds.

test/api.test.ts
const { test, beforeAll, afterAll, deploy, destroy } = Test.make({
  providers: Cloudflare.providers(),
  dev: !!process.env.LOCAL, // emulated, or the real cloud
});

const stack = beforeAll(deploy(Stack)); // its own stage
afterAll(destroy(Stack));

test("PUT + GET round-trips through R2", Effect.gen(function* () {
  const { url } = yield* stack;
  const res = yield* HttpClient.get(`${url}/object/hello.txt`);
  expect(yield* res.text).toBe("hi!");
}));
CI · pr-1729TEST
$

CI/CD · preview per PR

Deploy a preview stage in CI before merging

CI deploys each pull request to its own stage, runs the same tests, and comments a link to try it. The comment is a resource in the same program, so it is updated on every push and deleted with the preview. Merging deploys to production.

alchemy.run.ts
const api = yield* Api;const pr = yield* Config.option(Config.Int("PULL_REQUEST"));const sha = yield* Config.String("GITHUB_SHA"); if (Option.isSome(pr)) {  yield* GitHub.Comment("Preview", {    owner: "acme",    repository: "my-app",    issueNumber: pr.value,    body: Output.interpolate`Preview: ${api.url} (${sha})`,    allowDelete: true,  });}

Production · monitoring

Disciplined monitoring on Day 1

Provide one Layer and every request is traced and logged with OpenTelemetry from the first deploy. Its datasets, dashboards and alert monitors are resources in the same program, so monitoring ships with the app. Swap the Layer to send telemetry to a different platform.

Loved by the people shipping with it

What builders say after putting Alchemy in front of their agents, their Cloudflare apps, and their production infrastructure.

Get started.

  1. Installpnpm add alchemy@latest effect
  2. Paste this into your coding agent
    Help me build an Alchemy app on Cloudflare. Start by reading https://alchemy.run/getting-started and follow it exactly: scaffold a fresh project, install the dependencies, create the `alchemy.run.ts` Stack with a single Cloudflare R2 Bucket (no Worker yet), and run `alchemy deploy` so I sign in to Cloudflare and provision the Bucket. Confirm the Bucket is live before moving on. Then STOP and ASK ME what I want to build. From there, consult only the docs you need for what I asked for — don't march me through every tutorial. A Worker only gets added later if what I want to build needs one (the tutorial covers that in part-2). Tutorial — foundations, work through whichever parts I haven't touched: https://alchemy.run/cloudflare/tutorial/part-1 First Stack (state store + first resource) https://alchemy.run/cloudflare/tutorial/part-2 Add a Worker https://alchemy.run/cloudflare/tutorial/part-3 Testing https://alchemy.run/cloudflare/tutorial/part-4 Local Dev (`alchemy dev`) https://alchemy.run/cloudflare/tutorial/part-5 CI/CD (per-PR previews from GitHub Actions) For everything else (Cloudflare deep-dives, guides, concepts), fetch https://alchemy.run/llms.txt — it's the index of the guide and concept docs. Use it to look up the specific page you need instead of guessing URLs. The per-resource API reference is indexed separately in https://alchemy.run/llms-full.txt — it's large, so only fetch it when you need a specific resource's reference page. Important: - Confirm with me before each deploy. Don't batch. - Do NOT instruct me to export CLOUDFLARE_ACCOUNT_ID or CLOUDFLARE_API_TOKEN. Alchemy stores credentials in profiles — `alchemy profile edit` (or the first `alchemy deploy`) prompts interactively for OAuth or an API token and saves it to ~/.alchemy/profiles.json. - Use pnpm: `pnpm add` to install packages and `pnpm alchemy deploy` to deploy. - If I'm migrating from Alchemy v1 (async/await), find the v1 migration guide via llms.txt and read it first.
  3. Shippnpm alchemy deploy