Stacks
A Stack is the top-level unit of deployment in Alchemy. It groups resources together, wires up providers, and tracks state across deploys.
Defining a Stack
Section titled “Defining a Stack”A Stack is just an Effect that you export default from a TypeScript
file:
import * as Alchemy from "alchemy";import * as Cloudflare from "alchemy/Cloudflare";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "MyApp", { providers: Cloudflare.providers(), state: Cloudflare.state() }, Effect.gen(function* () { const bucket = yield* Cloudflare.R2.Bucket("Bucket"); return { bucketName: bucket.bucketName }; }),);Alchemy.Stack takes three arguments:
- Name — identifies this stack in state storage
- Options —
providersandstate, both required (see State Store for the available state layers) - Effect — a generator that declares resources and returns outputs
Stack outputs
Section titled “Stack outputs”The value returned from the generator becomes the stack output. After a deploy, outputs are printed to the console and available programmatically in tests.
Effect.gen(function* () { const bucket = yield* Cloudflare.R2.Bucket("Bucket"); const worker = yield* Worker;
return { bucketName: bucket.bucketName, url: worker.url, };});The CLI renders them after every successful deploy:
Stages
Section titled “Stages”Every deploy targets a stage — an isolated instance of the stack
like dev_sam, staging, or prod. The stage defaults to
dev_$USER, so each developer gets their own environment
automatically. State and physical names are namespaced by stage.
# Each stage = its own state file + its own physical names.$ alchemy deploy --stage dev_sam # -> myapp-dev_sam-photos-a3f1$ alchemy deploy --stage pr-147 # -> myapp-pr_147-photos-9b2c$ alchemy deploy --stage prod # -> myapp-prod-photos-7d4e
# Three independent deployments. Destroying one# never touches the others.For naming patterns, isolation, and per-stage configuration see Stages. Credentials per environment are managed via Profiles.
Accessing the Stack
Section titled “Accessing the Stack”Inside a resource or layer, you can access the current Stack’s
metadata via the Stack service:
import { Stack } from "alchemy/Stack";import * as Console from "effect/Console";
Effect.gen(function* () { const stack = yield* Stack; yield* Console.log(stack.name); // "MyApp" yield* Console.log(stack.stage); // "dev_sam"
const queue = yield* SQS.Queue("Jobs").pipe( RemovalPolicy.retain(stack.stage === "prod"), );});Stack.useSync for module-scope resources
Section titled “Stack.useSync for module-scope resources”When you declare a resource at module scope (outside any
Effect.gen), there is no yield* available to read the Stack
service. But a Resource’s props can themselves be an Effect —
Stack.useSync builds one that computes props from the current
stack, useful for parameterizing names by stage:
import * as Axiom from "alchemy/Axiom";import { Stack } from "alchemy/Stack";
export const Traces = Axiom.Dataset( "Traces", Stack.useSync(({ stage }) => ({ name: `${stage}-traces`, kind: "otel:traces:v1" as const, description: `OTEL traces for stage '${stage}'`, retentionDays: 30, })),);The function runs once at plan time, after the stage is resolved.
Use it anywhere a resource accepts a props object.
Cross-stack references
Section titled “Cross-stack references”A typed Alchemy.Stack handle lets one stack read another’s
persisted outputs at plan time:
// backend/src/Stack.ts — typed handle shared across packagesexport class Backend extends Alchemy.Stack< Backend, { url: string }>()("Backend") {}// frontend/alchemy.run.ts — reads the matching stage of Backendimport { Backend } from "backend";
export default Alchemy.Stack( "Frontend", { providers: Cloudflare.providers(), state: Cloudflare.state(), }, Effect.gen(function* () { const backend = yield* Backend;
const website = yield* Cloudflare.Website.Vite("Website", { env: { VITE_API_URL: backend.url }, });
return { url: website.url.as<string>() }; }),);yield* Backend defaults to the current stage — sam
frontend reads sam backend, pr-42 reads pr-42. Use
Backend.stage.<name> to pin to a specific stage instead.
See References for the underlying operators and Monorepo for the end-to-end walkthrough (package layout, schema sharing, deploy ordering).
A stack is just the container — the things it deploys are Resources.