Part 1: Your First Stack
In this first part you’ll install Alchemy and Effect, create a Stack with a Cloudflare R2 Bucket, and deploy it — all in under five minutes.
Prerequisites
Section titled “Prerequisites”- Bun (recommended) or Node.js 20+
- A Cloudflare account
Create a project
Section titled “Create a project”Start with an empty directory and initialize a package.json:
mkdir my-app && cd my-app && bun init -ymkdir my-app && cd my-app && npm init -ymkdir my-app && cd my-app && pnpm initmkdir my-app && cd my-app && yarn init -yInstall dependencies
Section titled “Install dependencies”Install alchemy@2.0.0-beta.10 and effect@4.0.0-beta.48:
bun add alchemy@2.0.0-beta.10 effect@4.0.0-beta.48 @effect/platform-bun@4.0.0-beta.48npm install alchemy@2.0.0-beta.10 effect@4.0.0-beta.48 @effect/platform-node@4.0.0-beta.48pnpm add alchemy@2.0.0-beta.10 effect@4.0.0-beta.48 @effect/platform-node@4.0.0-beta.48yarn add alchemy@2.0.0-beta.10 effect@4.0.0-beta.48 @effect/platform-node@4.0.0-beta.48Create the Stack
Section titled “Create the Stack”Every Alchemy program starts with a Stack — a collection of
Resources managed by Providers with state tracked between deploys.
Create an alchemy.run.ts file:
import * as import Alchemy
Alchemy from "alchemy";import * as import Effect
Effect from "effect/Effect";import * as import Layer
Layer from "effect/Layer";
export default import Alchemy
Alchemy.Stack<void, never>(stackName: string, options: { providers: Layer.Layer<never, never, StackServices>;}, eff: Effect.Effect<void, never, StackServices>): Effect.Effect<CompiledStack<void, any>, never, never> (+2 overloads)export Stack
Stack( "MyApp", { providers: Layer.Layer<never, never, StackServices>
providers: import Layer
Layer.const empty: Layer.Layer<never, never, never>
A Layer that constructs an empty Context.
This layer provides no services and can be used as a neutral element
in layer composition or as a starting point for building layers.
empty, }, import Effect
Effect.const gen: <never, void>(f: () => Generator<never, void, never>) => Effect.Effect<void, never, never> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
gen(function* () { // we'll add resources here next }),);This is a valid program, but it doesn’t do anything yet. The
Layer.empty providers and empty generator body are placeholders.
Add a Resource
Section titled “Add a Resource”Resources represent cloud infrastructure — buckets, queues, functions,
databases, and so on. Each resource is yield*-ed inside the Stack’s
Effect generator.
Let’s add a Cloudflare R2 Bucket to our Stack and observe the type error:
import * as import Alchemy
Alchemy from "alchemy";import * as import Cloudflare
Cloudflare from "alchemy/Cloudflare";import * as import Effect
Effect from "effect/Effect";import * as import Layer
Layer from "effect/Layer";
export default import Alchemy
Alchemy.Stack<void, Cloudflare.Providers>(stackName: string, options: { providers: Layer.Layer<NoInfer<Cloudflare.Providers>, never, StackServices>;}, eff: Effect.Effect<void, never, StackServices | Cloudflare.Providers>): Effect.Effect<CompiledStack<void, any>, never, never> (+2 overloads)export Stack
Stack( "MyApp", { providers: import Layer
Layer.const empty: Layer.Layer<never, never, never>
A Layer that constructs an empty Context.
This layer provides no services and can be used as a neutral element
in layer composition or as a starting point for building layers.
empty,Error ts(2322) ― }, import Effect
Effect.const gen: <Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers>, void>(f: () => Generator<Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers>, void, never>) => Effect.Effect<void, never, Cloudflare.Providers> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
gen(function* () { const const bucket: Cloudflare.R2Bucket
bucket = yield* import Cloudflare
Cloudflare.const R2Bucket: (id: string, props?: { name?: Alchemy.Input<string | undefined>; storageClass?: Alchemy.Input<Cloudflare.R2Bucket.StorageClass | undefined>; jurisdiction?: Alchemy.Input<Cloudflare.R2Bucket.Jurisdiction | undefined>; locationHint?: Alchemy.Input<Cloudflare.R2Bucket.Location | undefined>;} | undefined) => Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers> (+2 overloads)
R2Bucket("Bucket"); }),);TypeScript is telling us that Layer.empty doesn’t provide
Cloudflare.Providers — the layer required by R2Bucket.
Fix the Providers
Section titled “Fix the Providers”Replace Layer.empty with Cloudflare.providers() to resolve the
type error:
import * as import Alchemy
Alchemy from "alchemy";import * as import Cloudflare
Cloudflare from "alchemy/Cloudflare";import * as import Effect
Effect from "effect/Effect";import * as import Layer
Layer from "effect/Layer";
export default import Alchemy
Alchemy.Stack<void, Cloudflare.Providers>(stackName: string, options: { providers: Layer.Layer<NoInfer<Cloudflare.Providers>, never, StackServices>;}, eff: Effect.Effect<void, never, StackServices | Cloudflare.Providers>): Effect.Effect<CompiledStack<void, any>, never, never> (+2 overloads)export Stack
Stack( "MyApp", { providers: Layer.Layer<NoInfer<Cloudflare.Providers>, never, StackServices>
providers: import Cloudflare
Cloudflare.const providers: () => Layer.Layer<Cloudflare.Providers | Alchemy.Provider<Command> | Alchemy.Provider<Alchemy.Random> | Cloudflare.CloudflareEnvironment | Cloudflare.Credentials, never, Alchemy.Stack | Alchemy.Stage | Scope | FileSystem | Path | Alchemy.DotAlchemy | HttpClient | ChildProcessSpawner | AuthProviders>
Cloudflare providers, bindings, and credentials for Worker-based stacks.
providers(), }, import Effect
Effect.const gen: <Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers>, void>(f: () => Generator<Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers>, void, never>) => Effect.Effect<void, never, Cloudflare.Providers> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
gen(function* () { const const bucket: Cloudflare.R2Bucket
bucket = yield* import Cloudflare
Cloudflare.const R2Bucket: (id: string, props?: { name?: Alchemy.Input<string | undefined>; storageClass?: Alchemy.Input<Cloudflare.R2Bucket.StorageClass | undefined>; jurisdiction?: Alchemy.Input<Cloudflare.R2Bucket.Jurisdiction | undefined>; locationHint?: Alchemy.Input<Cloudflare.R2Bucket.Location | undefined>;} | undefined) => Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers> (+2 overloads)
R2Bucket("Bucket"); }),);Now the program type-checks. The providers layer tells Alchemy how to talk to Cloudflare’s APIs, and the type system ensures you never forget to wire it up.
Return Stack outputs
Section titled “Return Stack outputs”Stack outputs let you see important values after a deploy. Return an object from the generator to expose them:
import * as import Alchemy
Alchemy from "alchemy";import * as import Cloudflare
Cloudflare from "alchemy/Cloudflare";import * as import Effect
Effect from "effect/Effect";
export default import Alchemy
Alchemy.Stack<{ bucketName: Alchemy.Output<string, never>;}, Cloudflare.Providers>(stackName: string, options: { providers: Layer<NoInfer<Cloudflare.Providers>, never, StackServices>;}, eff: Effect.Effect<{ bucketName: Alchemy.Output<string, never>;}, never, StackServices | Cloudflare.Providers>): Effect.Effect<CompiledStack<{ bucketName: Alchemy.Output<string, never>;}, any>, never, never> (+2 overloads)export Stack
Stack( "MyApp", { providers: Layer<NoInfer<Cloudflare.Providers>, never, StackServices>
providers: import Cloudflare
Cloudflare.const providers: () => Layer<Cloudflare.Providers | Alchemy.Provider<Command> | Alchemy.Provider<Alchemy.Random> | Cloudflare.CloudflareEnvironment | Cloudflare.Credentials, never, Alchemy.Stack | Alchemy.Stage | Scope | FileSystem | Path | Alchemy.DotAlchemy | HttpClient | ChildProcessSpawner | AuthProviders>
Cloudflare providers, bindings, and credentials for Worker-based stacks.
providers(), }, import Effect
Effect.const gen: <Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers>, { bucketName: Alchemy.Output<string, never>;}>(f: () => Generator<Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers>, { bucketName: Alchemy.Output<string, never>;}, never>) => Effect.Effect<{ bucketName: Alchemy.Output<string, never>;}, never, Cloudflare.Providers> (+1 overload)
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to Use
gen allows you to write code that looks and behaves like synchronous
code, but it can handle asynchronous tasks, errors, and complex control flow
(like loops and conditions). It helps make asynchronous code more readable
and easier to manage.
The generator functions work similarly to async/await but with more
explicit control over the execution of effects. You can yield* values from
effects and return the final result at the end.
gen(function* () { const const bucket: Cloudflare.R2Bucket
bucket = yield* import Cloudflare
Cloudflare.const R2Bucket: (id: string, props?: { name?: Alchemy.Input<string | undefined>; storageClass?: Alchemy.Input<Cloudflare.R2Bucket.StorageClass | undefined>; jurisdiction?: Alchemy.Input<Cloudflare.R2Bucket.Jurisdiction | undefined>; locationHint?: Alchemy.Input<Cloudflare.R2Bucket.Location | undefined>;} | undefined) => Effect.Effect<Cloudflare.R2Bucket, never, Cloudflare.Providers> (+2 overloads)
R2Bucket("Bucket");
return { bucketName: const bucket: Cloudflare.R2Bucket
bucket.bucketName,bucketName: Alchemy.Output<string, never>
}; }),);Deploy
Section titled “Deploy”Set your Cloudflare environment variables.
export CLOUDFLARE_ACCOUNT_ID=your_account_id_hereexport CLOUDFLARE_API_TOKEN=your_api_token_hereRun alchemy deploy to create the Bucket on Cloudflare:
bun alchemy deploynpm run alchemy deploypnpm alchemy deployyarn alchemy deployPlan: 1 to create + Bucket (Cloudflare.R2Bucket) Proceed? ◉ Yes ○ No ✓ Bucket (Cloudflare.R2Bucket) created { bucketName: "myapp-bucket-a1b2c3d4e5", }
Alchemy shows a plan, asks for confirmation, creates the resource, and prints the stack outputs. Your bucket is live on Cloudflare.
Verify it worked
Section titled “Verify it worked”Your newly created R2 bucket will be listed on the Cloudflare R2 Object Storage Dashboard.
Run alchemy deploy again. Because nothing changed, the bucket shows
as a no-op:
Plan: no changes { bucketName: "myapp-bucket-a1b2c3d4e5", }
This is the core loop — declare resources in code, deploy, and Alchemy figures out what changed.
You now have:
- An
alchemy.run.tswith a Stack and a Cloudflare R2 Bucket - A live bucket deployed to your Cloudflare account
- Stack outputs showing the bucket name
In Part 2, you’ll add a Cloudflare Worker that uses this bucket to serve HTTP requests.