Alchemy v1 uses async/await with top-level await for
orchestration. Alchemy v2 replaces this with Effect generators for
type-safe error handling, composable retries, and declarative
resource wiring. The v1 documentation lives at
v1.alchemy.run.
Your existing async fetch handlers do not need to change — you
can keep them as-is and still get all the benefits of the new engine.
Your existing Worker runtime code does not need to change. The async
pattern declares bindings on the Worker’s env prop and uses
Cloudflare.InferEnv to type the env object:
alchemy.run.ts
exporttype
type WorkerEnv = Cloudflare.InferEnv<any>
WorkerEnv=
Cloudflare.
type Cloudflare.InferEnv = /*unresolved*/ any
InferEnv<typeof
const Worker: any
Worker>;
exportconst
const Worker: any
Worker=
any
Cloudflare.
any
Worker("Worker", {
main: string
main:"./src/worker.ts",
env: {
Bucket: any;
}
env: {
type Bucket: any
Bucket },
});
Your handler stays the same — just update the type import:
@param ― init A structured value that contains settings for the fetch() request.
@returns ― A promise that resolves to Response object.
fetch(
request: Request
request:
var Request: {
new (requestInfo: string, init?: RequestInit): Request;
new (requestInfo: RequestInit & {
url: string;
}): Request;
new (requestInfo: Request, init?: RequestInit): Request;
prototype: Request;
}
Request,
env: Env
env:
import WorkerEnv
WorkerEnv) {
const
constobject: any
object=await
env: Env
env.
any
BUCKET.
any
get("key");
const
constobject: any
object=await
env: Env
env.
any
Bucket.
any
get("key");
returnnew
var Response: new (body?: Bun.BodyInit | null | undefined, init?: ResponseInit | undefined) => Response
Response(
constobject: any
object?.
any
body??null);
},
};
Cloudflare.InferEnv derives a fully typed env object from the
env declared on the Worker. You get type safety on the binding
names and their APIs without using Effect in your runtime code.
Your v1 state is not compatible with v2, so v2 starts from an empty
state store. Without extra steps, the first deploy would create
brand-new resources alongside your existing ones. Instead, you
adopt the resources v1 already deployed —
no destroy, no downtime.
Adoption works by physical name: when a resource has no prior state,
the engine looks it up in the cloud by name and takes ownership of
what it finds. But v1 and v2 derive default names differently, so
without pinning, v2 would look for names that don’t exist.
When you didn’t set name explicitly, v1 derived it as:
{app}-{id}-{stage}
{app} — the name you passed to await alchemy("my-app")
{id} — the resource’s logical ID, e.g. await Bucket("bucket")
{stage} — the --stage value; defaults to $ALCHEMY_STAGE, then
your OS username ($USER), then dev
So the v1 example at the top of this page, deployed with
--stage prod, created a bucket named my-app-bucket-prod and a
worker named my-app-worker-prod. (Resources created inside a nested
scope get the scope names between {app} and {id}, and Worker names
are lowercased.)
Set the name prop on each v2 resource to that exact name:
If you did set name in v1, carry that value over unchanged. When in
doubt, confirm the live names in your v1 state (.alchemy/ by
default) or the Cloudflare dashboard.
Because v1 baked the stage into the name, each stage has different
physical names. If you deploy several stages from the same config,
compute the name from the stage (e.g. an environment variable your CI
sets) instead of hardcoding one stage’s suffix.
For each resource, the engine finds the existing one by its physical
name and adopts it into v2 state, then reconciles it to the declared
config. --adopt tells the engine to take over resources it cannot
prove it owns — which is exactly the situation for everything v1
created. See Adopting Resources for the
full ownership rules.
Server-side representation of an incoming HTTP request.
Details
It extends HttpIncomingMessage with request metadata, parsed cookies,
multipart accessors, WebSocket upgrade support, and a modify method for
creating adjusted request views.
Service tag for the active server-side HTTP request.
When to use
Use to access the request currently being handled by HTTP server routes and
middleware.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Server-side representation of an incoming HTTP request.
Details
It extends HttpIncomingMessage with request metadata, parsed cookies,
multipart accessors, WebSocket upgrade support, and a modify method for
creating adjusted request views.
Service tag for the active server-side HTTP request.
When to use
Use to access the request currently being handled by HTTP server routes and
middleware.
Split a string into substrings using the specified separator and return them as an array.
@param ― separator A string that identifies character or characters to use in separating the string. If omitted, a single-element array containing the entire string is returned.
@param ― limit A value used to limit the number of elements returned in the array.
split("/").
Array<string>.pop(): string |undefined
Removes the last element from an array and returns it.
If the array is empty, undefined is returned and the array is not modified.
The Worker resource declaration moves from alchemy.run.ts into the
Worker file itself (using import.meta.url as the main), and the
Stack just yield*-s the imported Worker:
alchemy.run.ts
import*as
import Alchemy
Alchemyfrom"alchemy";
import*as
import Cloudflare
Cloudflarefrom"alchemy/Cloudflare";
import*as
import Effect
Effectfrom"effect/Effect";
import
import Worker
var Worker: Effect.Effect<Pipeable & Alchemy.ResourceLike<"Cloudflare.Worker", Cloudflare.WorkerProps<{
Path to the Worker's entry module. Bundled with rolldown before
upload. Mutually exclusive with
script
— provide exactly one.
main:"./src/worker.ts",
env?:Alchemy.Input<{
readonlyBucket: any;
} | undefined>
Environment variables and native Cloudflare Bindings to bind to
the Worker. Accepts:
Resource references (R2 bucket, KV namespace, D1 database,
another Worker, Durable Object, etc.) — emitted as the
corresponding native binding.
effect/Config values (Config.redacted, Config.string,
Config.number, …) — resolved at deploy time and bound as
secret_text on Cloudflare regardless of the Config
constructor used. See
Secrets & env.
In Effect-native Workers you can alternatively yield* a
Config in the Init phase to register the binding implicitly;
env is the only option for async (non-Effect) Workers.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.