Skip to content

CLI

Terminal window
pnpm alchemy <command> [options]

Every command operates on an alchemy.run.ts stack file (or a custom entrypoint passed with --config <file>, which must exist) and targets a stage.

Terminal window
alchemy
├─ deploy # plan → approve → apply
├─ plan # preview changes, apply nothing
├─ destroy # delete every resource in a stage
├─ drift # detect (and optionally repair) infrastructure drift
├─ unsafe nuke # delete everything a provider can list, tracked or not
│
├─ dev # hot-reloading development loop
├─ logs # fetch past log entries, or tail live with --tail
│
├─ profile create|rename|edit|refresh|current|list|show|delete
│ # manage credentials and accounts (bare `profile` opens the dashboard)
│
├─ state list|read|delete # inspect and manage the state store (bare `state` opens the explorer)
├─ state bootstrap|teardown|logs # provision, delete, or debug a provider's state store (--backend)
│
└─ provider
├─ check-env # CI preflight: verify required provider env vars are set
├─ aws bootstrap|teardown # the deploy assets bucket
├─ cloudflare token
└─ prisma generate

Each command has its own page: deploy, plan, destroy, drift, unsafe nuke, dev, logs, profile, state, AWS provider commands, and Cloudflare provider commands. The workflow guides cover adopting resources and inspecting state. To run the same operations from a script, see the Programmatic API.

Option Description
--stage <name> Stage to target. Falls back to $ALCHEMY_STAGE, then live_$USER (dev_$USER for alchemy dev). Must match [a-z0-9]+([-_a-z0-9]+)*.
--profile <name> Auth profile from ~/.alchemy/profiles.json. Overrides $ALCHEMY_PROFILE; defaults to default.
--env-file <path> File to load environment variables from. Defaults to .env.
--yes Yes to all prompts.
--no-input Disable prompts and the interactive TUI. Commands that would need input fail instead of hanging.
--config, -c <file> Stack entrypoint. Defaults to alchemy.run.ts; must exist.
--fast-distilled Under Node, load each distilled SDK operation on first use. This lowers the CLI’s memory and startup time for stacks that import whole providers. Same as ALCHEMY_FAST_DISTILLED=1.

Use --profile with deploy, plan, destroy, dev, logs, drift, or state.

In an interactive terminal, deploy, destroy, and plan render a live TUI: the rendered plan, an arrow-key approval prompt, and per-resource apply progress that unmounts into the final output. Everywhere else the same commands emit plain line-oriented logs.

The --no-input flag and environment variables override the detection, in this order:

Signal Effect
--no-input flag Force plain output
ALCHEMY_PLAIN=1 or ALCHEMY_NO_TUI=1 Force plain output
ALCHEMY_TUI=1 Force the TUI
No TTY, CI=1, or a known agent env var (CLAUDECODE, CLAUDE_CODE_ENTRYPOINT, CURSOR_AGENT, AIDER_MODEL, CODEX_CLI) Force plain output

Interactive terminals use the animated TUI; redirected and non-interactive runs use append-only output.

Plain mode never prompts — it prints the plan, makes no changes, and fails with error: Cannot approve this operation without terminal input. Pass --yes to continue. In CI, always pass --yes.

Every log line is a record. Output from child processes (dev servers, workerd, the local provider sidecar) is captured as records too, so it can be shown either way:

Option Description
--log-format pretty|json pretty (default) prints lines; json prints one record per line on stderr, with child output as written. Also $ALCHEMY_LOG_FORMAT.
--log-level <level> Lowest level printed. Defaults to info. Also $ALCHEMY_LOG_LEVEL.

Every record has the same keys:

Key Value
time Unix time in milliseconds
level trace, debug, info, warn, error or fatal
kind log, event, output or run (see below)
process The alchemy process that produced it: cli, exec (the alchemy dev worker) or sidecar
scope project or global
trace { traceId, spanId } of the span it was logged in, or of the process outside any span. Child processes and sidecar calls join their caller’s trace.
attributes Annotations on the record, including fqn when it is about a resource
data Depends on kind
kind data
log { message, cause }: a line alchemy logged
event A typed event, as Alchemist.onEvent receives it
output { stream, text }: a line a child process wrote, exactly as written, ANSI styling included
run { version, pid, cwd, argv }: the first line of a run log
{"time":1793186948542,"level":"info","kind":"output","process":"sidecar","scope":"project","trace":{"traceId":"4bf92f3577b34da6a3ce929d0e0e4736","spanId":"00f067aa0ba902b7"},"attributes":{"fqn":"Web"},"data":{"stream":"stdout","text":"\u001b[32mready\u001b[39m on http://localhost:4321"}}

Each run also writes its records at debug level to a run log, one record per line. Project work goes to the project’s .alchemy/log/<time>-pid<pid>.ndjson; account-level work (the state store, auth and credentials, profile and provider commands) goes to ~/.alchemy/logs/<time>-pid<pid>.ndjson. A file is created only when a record goes to it. Child processes send their records through the CLI, so jq filters such as select(.kind == "output" and .attributes.fqn == "Api") find any of them.

Logs never leave your machine. Telemetry sends only usage spans and metrics; when reporting a problem, attach the run log.

Exit codes are script-safe: 0 only means the command actually completed.

Code Meaning
0 Command completed
1 Failure, including a declined plan or bare profile/state without a terminal
130 Cancelled by the user (Ctrl-C, or Escape inside a prompt)

Running these commands in a pipeline? See CI.

  • deploy — plan, approve, and apply changes
  • dev — hot-reloading development loop
  • profile manages credentials and connected accounts
  • state — inspect and manage the state store
  • Stages — how environments are isolated
  • CI — run the CLI in pipelines