1---
2title: Command
3description: Alchemy's cloud-agnostic primitives for local processes in the deploy graph — memoized builds, one-off commands, and dev servers.
4---
5
6The Command provider puts local child processes into the Stack's
7dependency graph: `Build` for a command that produces an output
8asset, `Exec` for a command run purely for its side effects, and
9`Dev` for a long-lived dev server. There is no setup — no
10credentials, nothing to configure. `Command.providers()` is already
11merged into both `AWS.providers()` and `Cloudflare.providers()`, so
12big-hub users have it for free; a standalone Stack registers it with
13`{ providers: Command.providers(), state: Alchemy.localState() }`.
14Import from `alchemy/Command`.
15
16## Resources
17
18`Build` runs a command that must produce an output asset (`outdir`)
19and tracks it in state:
20
21```typescript
22const build = yield* Command.Build("vite-build", {
23 command: "npm run build",
24 cwd: "./frontend",
25 outdir: "dist",
26});
27yield* Console.log(build.outdir); // path to the dist directory, relative to process.cwd()
28yield* Console.log(build.hash.output); // hash of the output files (when memo is enabled)
29```
30
31Inputs are content-hashed by default, so an unchanged project skips
32the rebuild entirely — see [Memoization](/command/memoization) for
33how the hash is computed and how to scope it.
34
35`Exec` runs a command purely for its side effects:
36
37```typescript
38yield* Command.Exec("codegen", {
39 command: "npm run codegen",
40 cwd: "./packages/api",
41});
42
43yield* Command.Exec("migrate", {
44 command: "npm run db:migrate",
45 env: {
46 DATABASE_URL: Redacted.make("postgres://..."),
47 },
48});
49```
50
51There is no output contract: the resource succeeds iff the command
52exits with code `0`, is skipped when its inputs are unchanged, and
53re-runs when the `command`, `env`, or memoized files change — e.g. a
54recreated database's connection URL with identical files. Deleting
55an `Exec` never reverses its side effects.
56
57`Dev` runs a long-lived process scoped to the stack instance:
58
59```typescript
60const dev = yield* Command.Dev("Frontend", {
61 command: "npm run dev",
62});
63yield* Console.log(dev.url); // e.g. "http://localhost:5173"
64```
65
66`Dev` only runs during `alchemy dev` — during `alchemy deploy` it is
67a no-op. See [Dev servers](/command/dev-servers) for the process
68lifecycle, restarts, and URL extraction.
69
70:::caution
71Command strings are whitespace-split into a binary and arguments —
72there is no quoting support unless you set `shell`. `Build`'s delete
73removes the output directory (`Exec`'s delete does nothing).
74`Redacted` env values are unwrapped at spawn time and kept out of
75logs and state.
76:::
77
78Pre-beta.58 `Build.Command` / `Build.DevServer` state converges
79automatically to `Command.Build` / `Command.Dev` on the next deploy
80([beta.58](/blog/2026-06-24-beta-58)).
81
82## Compose with your cloud
83
84The static-site guides for
85[Cloudflare](/cloudflare/frontend/static-site) and
86[AWS](/aws/frontend/static-site) create a `Command.Build` (and, in
87dev mode, a `Command.Dev`) under the hood, and
88[`alchemy dev`](/cli/dev) is the loop that hosts `Dev` processes.
89
90## Reference
91
92[Build](/providers/command/build) ·
93[Dev](/providers/command/dev) ·
94[Exec](/providers/command/exec)