References
A reference reads something already deployed — a different stage, a different Stack, or both — from the persisted state store at plan time. References are lazy and don’t drift: every plan re-reads the upstream’s state, so downstream always sees whatever was actually last deployed.
Reference another stage
Section titled “Reference another stage”Resource.ref takes a
Logical ID; pass
stage to read that Resource from a different stage of this stack:
const { stage } = yield* Alchemy.Stack;
const project = stage.startsWith("pr-") ? yield* Neon.Project.ref("app-db", { stage: "staging" }) : yield* Neon.Project("app-db", { region: "aws-us-east-1" });The ref has the same type as yield* Neon.Project("app-db", { … })
— pass it anywhere the real thing is accepted. Here staging owns
the database and pr-* stages borrow it; destroying a borrower
never touches the Resources it references.
Reference another Stack
Section titled “Reference another Stack”Pass stack too for a Resource in a different Stack:
const sharedBucket = yield* Storage.Bucket.ref("Assets", { stack: "shared-infra", stage: "prod",});{ stack, stage, id } is the full address; anything you omit
defaults to the current stack/stage. Pin stage when the stacks’
stages don’t line up — pr-147 has no counterpart in
shared-infra.
Depend on a Stack’s outputs
Section titled “Depend on a Stack’s outputs”When the unit you consume is a whole Stack, import its tag and yield it:
export class Backend extends Alchemy.Stack< Backend, { url: string }>()("Backend") {}// inside the frontend Stack's Effect.genconst a = yield* Backend; // current stageconst b = yield* Backend.stage.prod; // pinned to "prod"const c = yield* Backend.stage["pr-42"]; // any stage nameDeclare the stages as a third type parameter and a misspelled stage becomes a type error:
export class Backend extends Alchemy.Stack< Backend, { url: string }, "prod" | `pr-${number}`>()("Backend") {}
const d = yield* Backend.stage[`pr-${pr}`];Every successful apply persists what the Stack’s effect returned
as a per-stage output record; yield* Backend reads it back as a
proxy of typed Outputs, so (yield* Backend).url is
Output<string>. Full two-package walkthrough:
Multiple Stacks.
Look up a resource Alchemy doesn’t manage
Section titled “Look up a resource Alchemy doesn’t manage”Resource.lookup finds a resource that no Alchemy stack deployed,
such as a Worker deployed with Wrangler or from the dashboard. Each
resource defines what it is found by. A Worker is found by its name:
const worker = yield* Cloudflare.Worker("Api", { main: "./src/api.ts", env: { AUTH: Cloudflare.Worker.lookup({ name: "auth-service" }), },});The lookup has the same type as a declared Worker, so env.AUTH is
a service binding. The lookup runs on every plan and fails the
deploy if nothing matches. Alchemy never creates, updates or deletes
a looked-up resource, and lookup is a type error on resources that
don’t support it.
Lookup props can be another resource’s outputs. The lookup waits for that resource, the same way a declared resource would. A Hyperdrive configuration can take its local dev origin from a database the stack creates:
const project = yield* Neon.Project("Db");const db = Cloudflare.Hyperdrive.Connection.lookup({ name: "shared-postgres", dev: project.origin,});A lookup is not a dependency, so don’t use one for a resource your
own stack declares: reference that resource directly. A lookup that
finds one of the stack’s own resources fails the deploy with
LookupOfManagedResourceError. A resource another Alchemy stack
manages is better found with Resource.ref, which reads that
stack’s state.
Escape hatches
Section titled “Escape hatches”When the Resource constructor isn’t in scope, Output.ref is the
same lookup:
const bucket = Output.ref<typeof Bucket>("Bucket", { stack: "shared-infra", stage: "prod",});When a typed Stack handle isn’t in scope, Output.stackRef reads
the output record directly:
const backend = yield* Output.stackRef<{ url: string }>("Backend", { stage: "prod",});Prefer Resource.ref and yield* MyStack — same lookups, real
type bindings.
Deploy order
Section titled “Deploy order”The upstream must already be deployed to the exact
{ stack, stage } the reference names, or the plan fails fast
with a typed InvalidReferenceError — there is no
deploy-and-hope path:
alchemy deploy --stage staging # creates app-dbalchemy deploy --stage pr-147 # borrows staging's app-dbDestroy in reverse order. Resolution itself is the in-stack Output flow with one difference: a reference’s upstream was reconciled by a previous deploy, so only its persisted attributes participate in this plan.
Where next
Section titled “Where next”- Resource Lifecycle — how the referenced state got persisted in the first place. Next page.
- Multiple Stacks — typed Stack handles wiring a monorepo.
- Shared database across stages — the owner/borrower pattern end to end.
- Inputs & Outputs — the Output model references plug into.
- State Store — where the persisted state that refs read lives.