CLI Reference
The Alchemy CLI manages the lifecycle of your stacks. Every command
operates on an alchemy.run.ts file (or a custom entrypoint) and
targets a stage — an isolated environment like dev_sam, prod,
or pr-42.
alchemy <command> [file] [options]If no file is specified, the CLI looks for alchemy.run.ts in the
current directory.
Common options
Section titled “Common options”These options are shared across most commands:
| Option | Description |
|---|---|
--stage <name> | Stage to target. Defaults to dev_$USER (e.g. dev_sam). Must match [a-z0-9][-_a-z0-9]*. |
--env-file <path> | Load environment variables from a file before running. |
deploy
Section titled “deploy”Compute a plan, ask for approval, and create/update/delete resources to match the desired state.
alchemy deploy [file] [options]Plan: 2 to create + Bucket (Cloudflare.R2Bucket) + Worker (Cloudflare.Worker) (1 bindings) + Bucket Proceed? ◉ Yes ○ No ✓ Bucket (Cloudflare.R2Bucket) created ✓ Worker (Cloudflare.Worker) created • Uploading worker (14.20 KB) ... • Enabling workers.dev subdomain... { url: "https://myapp-worker-dev-you-abc123.workers.dev", }
On subsequent deploys, only changed resources are updated:
Plan: 1 to update ~ Worker (Cloudflare.Worker) Proceed? ◉ Yes ○ No ✓ Worker (Cloudflare.Worker) updated • Uploading worker (15.10 KB) ... { url: "https://myapp-worker-dev-you-abc123.workers.dev", }
| Option | Description |
|---|---|
--stage <name> | Stage to deploy to (defaults to dev_$USER) |
--yes | Skip the approval prompt |
--dry-run | Show the plan without applying (same as alchemy plan) |
--force | Force updates for resources that would otherwise no-op |
--adopt | Adopt pre-existing cloud resources that conflict with this stack instead of failing. Useful for re-importing into a fresh state store. |
--profile <name> | Auth profile to use (defaults to default or $ALCHEMY_PROFILE) |
--env-file <path> | Load environment variables from a file |
# Deploy to production, skip the promptalchemy deploy --stage prod --yes
# Deploy a different stack filealchemy deploy stacks/github.ts
# Preview what would changealchemy deploy --dry-run
# Re-import existing cloud resources into a fresh state storealchemy deploy --adoptAdoption
Section titled “Adoption”When a resource has no prior state, the engine calls the provider’s
read to check whether the resource already exists in the cloud. The
return value drives one of three paths:
read returns | Without --adopt | With --adopt |
|---|---|---|
undefined | create | create |
| owned (plain attrs) | silent adopt | silent adopt |
Unowned(attrs) | fail OwnedBySomeoneElse | take over (silently) |
“Owned” means the provider can prove the resource was created by this stack/stage/logical-id — typically by inspecting tags or a naming convention. Recovering a wiped state store for resources you already own is the default behavior: no flag required.
--adopt only matters when the provider reports a resource exists
but isn’t ours. That’s the deliberately load-bearing case: by
default Alchemy refuses to silently overwrite tags/config of a
resource it can’t prove ownership of. --adopt says “yes, take it
over.”
# Re-import existing alchemy-tagged resources into a fresh state# store — no flag needed for these. Ones with foreign ownership tags# will surface as `OwnedBySomeoneElse` errors.alchemy deploy
# Force takeover of any conflicting resource regardless of tags.alchemy deploy --adoptYou can also enable adoption programmatically by piping the
adopt combinator onto a deploy effect from alchemy/AdoptPolicy:
import { adopt } from "alchemy/AdoptPolicy";
yield* deploy( Effect.gen(function* () { yield* Cloudflare.Worker("API", { /* ... */ }); }),).pipe(adopt(true));AdoptPolicy is consulted at plan time, so the combinator must
wrap the deploy (or test runner’s stack.deploy(...)) — not the
inner resource-declaration effect.
Resources without ownership semantics (e.g. APIs that always
return a singleton by name, with no tag concept) silently adopt
unconditionally — --adopt is a no-op for them.
Preview what would change without applying anything. Equivalent to
alchemy deploy --dry-run.
alchemy plan [file] [options]Plan: 1 to create, 1 to update + Queue (AWS.SQS.Queue) ~ Worker (Cloudflare.Worker)
The plan uses + for creates, ~ for updates, - for deletes,
and • for no-ops. No approval prompt is shown and no changes are
made.
| Option | Description |
|---|---|
--stage <name> | Stage to plan against (defaults to dev_$USER) |
--env-file <path> | Load environment variables from a file |
destroy
Section titled “destroy”Delete every resource in a stack. Computes a plan where all existing resources are marked for deletion, asks for approval, and removes them in dependency order.
alchemy destroy [file] [options]Plan: 2 to delete - Worker (Cloudflare.Worker) - Bucket (Cloudflare.R2Bucket) Proceed? ◉ Yes ○ No ✗ Worker (Cloudflare.Worker) deleted ✗ Bucket (Cloudflare.R2Bucket) deleted
| Option | Description |
|---|---|
--stage <name> | Stage to destroy (defaults to dev_$USER) |
--yes | Skip the approval prompt |
--dry-run | Show what would be deleted without actually deleting |
--env-file <path> | Load environment variables from a file |
# Destroy a PR preview environmentalchemy destroy --stage pr-42 --yesRun your stack in development mode with hot reloading.
alchemy dev [file] [options]Resources are deployed to the cloud while Workers run locally in workerd. File changes trigger automatic rebuilds and hot reloads.
| Option | Description |
|---|---|
--stage <name> | Stage to use for dev (defaults to dev_$USER) |
--env-file <path> | Load environment variables from a file |
# Start dev modealchemy dev
# Use a custom stagealchemy dev --stage devStream live logs from deployed resources in real time.
alchemy tail [file] [options]Tailing: Worker, Api 2026-04-15 14:32:01.123 PST [Worker] GET /hello.txt 200 2026-04-15 14:32:01.456 PST [Worker] PUT /world.txt 201 2026-04-15 14:32:02.789 PST [Api] POST /api/data 200
Logs from multiple resources are interleaved and color-coded by
resource. The command streams indefinitely until you interrupt it
with Ctrl+C.
| Option | Description |
|---|---|
--stage <name> | Stage to tail (defaults to dev_$USER) |
--filter <ids> | Comma-separated logical resource IDs to include (e.g. Worker,Api) |
--env-file <path> | Load environment variables from a file |
# Tail only the Worker resourcealchemy tail --filter Worker
# Tail a specific stagealchemy tail --stage prodFetch historical logs from deployed resources.
alchemy logs [file] [options]Unlike tail, logs fetches a batch of past log entries and exits.
| Option | Description |
|---|---|
--stage <name> | Stage to fetch logs from (defaults to dev_$USER) |
--filter <ids> | Comma-separated logical resource IDs to include |
--limit <n> | Number of log entries to fetch (default: 100) |
--since <time> | Fetch logs since this time — a duration (1h, 30m, 2d) or ISO date |
--env-file <path> | Load environment variables from a file |
# Last 50 log entries from all resourcesalchemy logs --limit 50
# Logs from the last hour, Worker onlyalchemy logs --filter Worker --since 1h
# Logs from a specific stage since a datealchemy logs --stage prod --since 2026-04-01T00:00:00Zbootstrap
Section titled “bootstrap”Set up the per-cloud infrastructure that Alchemy itself relies on — the AWS assets bucket used for Lambda artifacts, or the Cloudflare state-store worker that holds your remote stack state.
alchemy bootstrap <provider> [options]The bootstrap command is split into provider-specific subcommands.
Run alchemy bootstrap <provider> --help to see the flags for each.
bootstrap aws
Section titled “bootstrap aws”Set up the AWS assets bucket required for deploying Lambda functions and other AWS resources that need artifact storage.
alchemy bootstrap aws [options]| Option | Description |
|---|---|
--profile <name> | AWS profile to use for credentials (default: default) |
--region <region> | AWS region to bootstrap (defaults to AWS_REGION env var) |
--destroy | Destroy all bootstrap buckets in the selected region |
--env-file <path> | Load environment variables from a file |
# Bootstrap with the default profilealchemy bootstrap aws
# Bootstrap a specific region and profilealchemy bootstrap aws --profile prod --region us-west-2
# Remove bootstrap resourcesalchemy bootstrap aws --destroybootstrap cloudflare
Section titled “bootstrap cloudflare”Manually deploy (or repair) the Cloudflare-hosted HTTP State Store —
the worker + Secrets Store + auth-token secret that back the
remote-state layer used by Cloudflare.state(...).
You normally don’t need to run this: the very first stack deploy
that uses Cloudflare.state(...) will prompt you to bootstrap
automatically. Use this command to re-run that flow on demand —
typically to recover from a previous deploy that was interrupted
mid-bootstrap.
alchemy bootstrap cloudflare [options]| Option | Description |
|---|---|
--profile <name> | Alchemy auth profile (defaults to default or $ALCHEMY_PROFILE). Determines which ~/.alchemy/profiles.json entry is used. |
--force | Force a full redeploy even if the worker already exists. Without this flag, an existing worker is adopted and only its credentials are refreshed. |
--worker-name <name> | Override the default state-store worker name. Advanced; only needed if you run multiple state stores per Cloudflare account. |
--env-file <path> | Load environment variables from a file |
The bootstrap is idempotent and self-healing:
- If the worker already exists in your Cloudflare account, it is
adopted: the auth token is re-fetched live via a short-lived
edge-preview probe (the only way to read a Secrets Store value),
and
~/.alchemy/credentials/<profile>/cloudflare-state-store.jsonis rewritten with the current token. - If a previous run failed mid-flight (e.g. the worker got created but credentials never landed on disk), the leftover local state stack is detected and the deploy resumes where it left off. The bootstrap is only considered complete once the local stack has been hoisted into the remote store and removed.
- With
--force, the deploy runs again unconditionally. Existing Cloudflare resources (worker, Secrets Store, secret) are still reconciled in place rather than replaced — adoption is enabled automatically for the bootstrap stack.
# First-time bootstrap (or repair after a failed deploy)alchemy bootstrap cloudflare
# Bootstrap a separate profilealchemy bootstrap cloudflare --profile staging
# Force a full redeploy (e.g. to roll out an updated state-store worker)alchemy bootstrap cloudflare --forceConfigure and log in to each cloud provider used by your stack. The
command imports your stack file to discover which AuthProviders are
registered, then walks through each one — prompting for the auth method
the first time, and refreshing tokens (e.g. Cloudflare OAuth) on
subsequent runs.
Credentials are written to ~/.alchemy/profiles.json, keyed by
profile name (defaults to default, overridable with
$ALCHEMY_PROFILE or --profile).
alchemy login [file] [options]| Option | Description |
|---|---|
--profile <name> | Profile to write to (defaults to default or $ALCHEMY_PROFILE) |
--configure | Re-run the provider’s interactive configure step before logging in |
--stage <name> | Stage used while loading the stack (defaults to dev_$USER) |
--env-file <path> | Load environment variables from a file |
# Log in with the default profilealchemy login
# Log in to a separate profilealchemy login --profile prod
# Re-configure (e.g. switch from OAuth to API token) and log inalchemy login --configureprofile
Section titled “profile”Inspect credentials stored in ~/.alchemy/profiles.json.
profile show
Section titled “profile show”Print every auth method configured under a profile, along with its
resolved credentials (redacted). Unlike login, this does not
import your stack file — it reads the profile store directly and uses
the bundled providers (Cloudflare, AWS) to pretty-print each entry.
alchemy profile show [options]Profile: default ── AWS ── accessKeyId: ASIA**** secretAccessKey: Pj5T**** sessionToken: IQoJ**** region: us-west-2 source: sso - default ── Cloudflare ── accessToken: Xl06**** expires: in 59m 58s 999ms (2026-04-27T20:45:47.937Z) accountId: 123456789... source: oauth
| Option | Description |
|---|---|
--profile <name> | Profile to show (defaults to default or $ALCHEMY_PROFILE) |
--env-file <path> | Load environment variables from a file |
# Show the default profilealchemy profile show
# Show a named profilealchemy profile show --profile prodInspect and manage the state store — the record of which resources
Alchemy thinks exist for each stack/stage. Reads from whatever state
layer the stack file configures (e.g. Cloudflare.state(...)), or
from the on-disk .alchemy/state directory with --local.
alchemy state <subcommand> [options]The stack file is imported to resolve its configured state layer, so
all subcommands accept the same --stage, --profile, and
--env-file options as deploy. Pass [file] via the standard
positional script argument inherited from the root command.
| Option | Description |
|---|---|
--local | Read from local .alchemy/state instead of the stack’s configured state store |
--stage <name> | Stage used while loading the stack (defaults to dev_$USER) |
--profile <name> | Auth profile to use (defaults to default or $ALCHEMY_PROFILE) |
--env-file <path> | Load environment variables from a file |
state stacks
Section titled “state stacks”List every stack name present in the state store.
alchemy state stacks [file] [options]state stages <stack>
Section titled “state stages <stack>”List every stage that has state recorded under <stack>.
alchemy state stages <stack> [file] [options]state resources <stack> <stage>
Section titled “state resources <stack> <stage>”List the fully-qualified resource names (FQNs) tracked under a given stack/stage.
alchemy state resources <stack> <stage> [file] [options]state get <stack> <stage> <fqn>
Section titled “state get <stack> <stage> <fqn>”Print a single resource’s persisted state as JSON. Output uses the
same encoding the store persists: redacted secrets are unwrapped into
{ __redacted__: ... } and Resources are flattened.
alchemy state get <stack> <stage> <fqn> [file] [options]state tree
Section titled “state tree”Render the entire state store as a tree of stacks → stages → resources.
alchemy state tree [file] [options]AlchemyEffectWebsite ├─ dev_sam │ ├─ Bucket │ └─ Worker └─ prod ├─ Bucket └─ Worker
state clear [stack] [stage]
Section titled “state clear [stack] [stage]”Delete state entries from the store. Destructive but local-only —
the actual cloud resources are not touched, only Alchemy’s record of
them. A subsequent deploy will see an empty state and try to
re-create everything (use --adopt to reconcile against existing
infrastructure).
alchemy state clear [stack] [stage] [file] [options]- Omit both arguments to clear all stacks in the store.
- Pass
<stack>to clear every stage under that stack. - Pass
<stack> <stage>to clear a single stage.
| Option | Description |
|---|---|
--yes | Skip the confirmation prompt |
# Inspect what's in the storealchemy state tree
# Drop a single PR-preview stagealchemy state clear myapp pr-42 --yes
# Wipe local state after a botched bootstrapalchemy state clear --localStages
Section titled “Stages”Every command targets a stage — an isolated instance of your
stack. The stage defaults to dev_$USER (e.g. dev_sam), so each
developer gets their own environment automatically.
alchemy deploy --stage prodalchemy deploy --stage pr-42alchemy destroy --stage dev_samResources are namespaced by stage. Physical names include the stage
(e.g. myapp-prod-bucket-abc123), so environments never interfere
with each other.