Skip to content

state

Terminal window
alchemy state [subcommand] [options]

Inspect 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 --backend local. See State Store.

Run alchemy state with no subcommand in an interactive terminal to open the state explorer. It shows stacks, stages, resources, and a YAML preview of the selected resource’s persisted state. Mark entries with Space and delete them with d; a confirm dialog lists the exact records before anything is removed. The subcommands below are the scriptable equivalents.

The stack file is imported only to resolve its configured state layer Pass it with --config, which defaults to alchemy.run.ts. There is no deploy-style --stage flag here: state commands address what they inspect explicitly through positional arguments.

All subcommands share these options:

Option Description
--backend <name> configured (default) uses the stack’s state layer; local reads .alchemy/state, including orphaned state after a failed bootstrap; a provider’s store (aws, cloudflare) is reached from the profile alone, without a stack file
--name <name> With a provider store, address one other than the default: a logical name on AWS and GCP (1-20 lowercase letters, digits and hyphens), the full Worker name on Cloudflare
--domain <host> With --backend cloudflare, the hostname the store is served on when it has a custom domain
--profile <name> Auth profile to use (defaults to $ALCHEMY_PROFILE or default)
--env-file <path> Load environment variables from a file
--config, -c <file> Stack entrypoint to resolve the state layer from (defaults to alchemy.run.ts)

--name, --domain and any other store option come from the installed providers’ state stores, and each backend takes only the flags it contributes. alchemy state --help lists them.

Terminal window
alchemy state list [path] [options] # alias: ls

State is addressed like a filesystem: <stack>/<stage>/<namespace…>/ <resource>, plus one output entry per stage holding the stack’s evaluated outputs. list prints one directory level; --recursive/-r walks the whole subtree.

Terminal window
alchemy state list # every stack
alchemy state list my-app # stages under my-app
alchemy state list my-app/prod # resource entries under my-app/prod
alchemy state list my-app -r # every path under my-app
Terminal window
alchemy state read [path] [options] # alias: cat

Print persisted state as JSON. A resource path prints that record; a directory path with --recursive prints every record beneath it, keyed by path. Output uses the same encoding the store persists: redacted secrets are unwrapped into { __redacted__: ... } and Resources are flattened.

Terminal window
# one resource record
alchemy state read my-app/prod/Bucket
# a whole stage as one JSON document for jq
alchemy state read my-app/prod -r | jq 'to_entries[] | select(.value.resourceType == "AWS.EC2.Instance")'
# diff two stages
diff <(alchemy state read my-app/dev -r) \
<(alchemy state read my-app/prod -r)
Terminal window
alchemy state delete <path> [options] # alias: rm

Delete state records. Deleting a stack or stage path removes everything beneath it; a directory path below stage level needs --recursive. output cannot be deleted independently. Alchemy removes it with its stage.

Option Description
--recursive, -r Operate recursively on directories
Terminal window
alchemy state bootstrap [--backend <name>] [options]

Provision a state store, or adopt it when it already exists. Idempotent. You normally don’t need it: the first deploy that uses the store provisions it. Run it to provision ahead of time (for example before CI uses the store), or to repair an interrupted bootstrap.

Without --backend it provisions the store your entrypoint (alchemy.run.ts, or --config) configures, with every option it sets, such as a custom Worker or bucket name, a pinned account or a domain. With --backend it provisions a provider’s default store, or the one --name names.

  • cloudflare: deploys the state-store Worker and creates its auth token and encryption key in the account’s Secrets Store when they are missing. Existing secrets are never changed. An existing Worker is adopted and its credentials (~/.alchemy/profiles/<profile>/state-stores/cloudflare.json) are refreshed.
  • aws: creates the state bucket with versioning, encryption, a public access block and owner-enforced ownership, or converges an existing one to those settings.
Option Description
--force cloudflare: redeploy the Worker even when it exists, keeping its secrets (with --backend)
Terminal window
alchemy state bootstrap
alchemy state bootstrap --backend cloudflare
alchemy state bootstrap --backend cloudflare --profile staging --force
alchemy state bootstrap --backend aws --name team-a
alchemy state bootstrap --backend cloudflare --name team-a
Terminal window
alchemy state teardown --backend <name> [options]

Delete a provider’s state store and its backing resources: the Cloudflare Worker, its secrets and cached credentials; or the S3 bucket with every object version. Asks for confirmation unless --yes.

Terminal window
alchemy state logs --backend <name> [options]

Fetch or stream the state store’s own logs, to debug the store itself. Only cloudflare keeps logs (from the state-store Worker, through the Workers Observability API), which needs the workers_observability:read and workers_observability_telemetry:write OAuth scopes (re-run alchemy profile edit --reconfigure Cloudflare on older profiles).

Option Description
--tail, -t Stream logs as they happen instead of fetching past entries
--limit <n> Number of entries to fetch (default: 100). Ignored with --tail
--since <time> Fetch logs since a duration (1h, 30m, 2d) or ISO date
Terminal window
alchemy state logs --backend cloudflare --since 30m --limit 200
alchemy state logs --backend cloudflare --tail