1---
2title: Machines
3description: A Firecracker VM running a container image.
4---
5
6A [`Fly.Machine`](/providers/fly/machine) is a Firecracker VM
7running a container image. Use it when you already have an image.
8
9## Launch a Machine
10
11A Machine runs in a [`Fly.App`](/fly/compute/apps) you declare:
12
13```typescript
14// src/app.ts
15export const Site = Fly.App("Site");
16```
17
18Pin a [region](/fly/compute/regions), an image, and a guest:
19
20```typescript
21const web = yield* Fly.Machine("Web", {
22 app: Site,
23 region: "iad",
24 image: "nginx:alpine",
25 guest: { cpuKind: "shared", cpus: 1, memoryMb: 256 },
26 services: [
27 {
28 protocol: "tcp",
29 internalPort: 80,
30 ports: [
31 { port: 80, handlers: ["http"], forceHttps: true },
32 { port: 443, handlers: ["tls", "http"] },
33 ],
34 },
35 ],
36});
37```
38
39`region` replaces on change. `image` updates in place by default; the
40opt-in blue/green strategy prepares replacement Machines instead. Guest
41defaults to shared-cpu 1× / 256 MB. Port 443 with `tls` is what
42makes `https://{app}.fly.dev` answer. Omit `services` (or pass
43`[]`) for a worker that should not be reachable from the internet.
44
45The App needs an
46[`IpAssignment`](/fly/networking#addresses-for-a-shared-app) before
47`{app}.fly.dev` answers over IPv4. For a public endpoint without
48managing Apps and addresses, use a [Service](/fly/compute/services).
49
50## Run named containers
51
52Use `containers` for a group that shares one Machine. Each named container has its own image and can set `cmd`, `entrypoint`, `env`, startup `dependsOn`, and Pilot `healthChecks`. Use `cmd` and `entrypoint` to override startup; container `exec` overrides are not supported. Existing single-image `init.exec` is unchanged. Check intervals and timeouts are numeric seconds. A dependency condition can be `started`, `healthy`, or `exited_successfully`.
53
54```typescript
55const preview = yield* Fly.Machine("Preview", {
56 app: Site,
57 region: "iad",
58 guest: { cpus: 1, memoryMb: 1024 },
59 containers: [
60 { name: "api", image: apiImage, healthChecks: [{ http: { port: 3000, path: "/health" } }] },
61 { name: "worker", image: workerImage, dependsOn: [{ name: "api", condition: "healthy" }] },
62 ],
63});
64```
65
66`count` duplicates the entire group. A rolling change to one container can restart the whole group; attached volumes stay with their Machine. Machine `env` and bindings remain shared, while container `env` is passed to Fly as a per-container override. Configure Machine or service readiness checks for every critical component before treating a deploy as ready: Pilot container checks and dependencies control startup, not Alchemy's rollout readiness. Blue/green also supports named containers when every image is an immutable
67`repository@sha256:` digest and no volumes are attached. It replaces the
68whole group and can overlap old and new workers during promotion.
69
70If a rolling update is interrupted, Fly may have accepted the update even
71though the CLI reported a failure. Wait for the in-progress Machine update to
72settle, then rerun the same desired deployment. Reconciliation reuses the
73owned Machine and its attached volumes.
74
75## Scale up
76
77A Machine resource runs one VM by default. Set `count` to manage
78several replicas together, or declare separate resources for Machines
79with different configuration. Fly's proxy load-balances published
80`services` across them.
81
82```typescript
83const web1 = yield* Fly.Machine("Web1", {
84 app: Site,
85 region: "iad",
86 image: "nginx:alpine",
87 services: [
88 {
89 protocol: "tcp",
90 internalPort: 80,
91 ports: [
92 { port: 80, handlers: ["http"], forceHttps: true },
93 { port: 443, handlers: ["tls", "http"] },
94 ],
95 },
96 ],
97});
98
99const web2 = yield* Fly.Machine("Web2", {
100 app: Site,
101 region: "iad",
102 image: "nginx:alpine",
103 services: [
104 {
105 protocol: "tcp",
106 internalPort: 80,
107 ports: [
108 { port: 80, handlers: ["http"], forceHttps: true },
109 { port: 443, handlers: ["tls", "http"] },
110 ],
111 },
112 ],
113});
114```
115
116Both `Fly.Machine` and [`Service`](/fly/compute/services) support
117`count`. With the default rolling strategy, replicas within one resource
118update sequentially; separate resources do not share that ordering.
119Blue/green prepares the desired replacement topology before old retirement.
120
121`count` is provisioned capacity, not always-running capacity. With
122`autostop: "stop"` or `"suspend"`, replicas may be idle. `autostart` allows
123requests to wake them, and `minMachinesRunning` controls Fly's running floor.
124Blue/green checks a running representative plus the required floor without
125permanently waking all idle replicas. A replacement does not inherit suspended
126RAM. See [idle-capacity semantics](/fly/compute/deployments#keep-idle-capacity-with-stop-or-suspend).
127
128## Scale down
129
130Remove a Machine from the stack. The next deploy deletes it.
131
132```diff lang="typescript"
133 const web1 = yield* Fly.Machine("Web1", {
134 app: Site,
135 region: "iad",
136 image: "nginx:alpine",
137 });
138-
139- const web2 = yield* Fly.Machine("Web2", {
140- app: Site,
141- region: "iad",
142- image: "nginx:alpine",
143- });
144```
145
146## Env, restart, metadata
147
148```typescript
149const worker = yield* Fly.Machine("Worker", {
150 app: Site,
151 region: "iad",
152 image: "my-image:tag",
153 env: { LOG_LEVEL: "info" },
154 restart: { policy: "always" },
155});
156```
157
158Alchemy stamps `alchemy.stack` / `alchemy.stage` / `alchemy.id` /
159`alchemy.type` onto `config.metadata` so `list()` can find owned
160Machines. Fly injects App [secrets](/fly/data/secrets) as env vars
161on the Machine. `minSecretsVersion` requires at least that secret version;
162it is a floor, not an immutable snapshot. Machine leases do not serialize
163standalone `Fly.Secret`, other Services, or runtime vault writers. A later
164writer can advance the shared App vault. Set an explicit deployment input
165or version floor when an out-of-band rotation requires a new rollout;
166secret changes are not automatically watched.
167
168## Mounts
169
170Pass disks as `mounts`. Alchemy creates a Volume in the Machine's
171app and region. A Volume attaches to one Machine.
172
173```typescript
174const box = yield* Fly.Machine("Box", {
175 app: Site,
176 region: "iad",
177 image: "nginx:alpine",
178 mounts: [{ path: "/data", sizeGb: 1 }],
179});
180```
181
182From a Service, prefer [`MountVolume`](/fly/data/volumes) so the
183path is part of the binding graph.
184
185## Lifecycle
186
187For replicas required to run, reconcile waits until the Machine is
188`started` (`waitMachine`, bounded). It then waits for configured readiness
189checks. With default rolling updates, this happens before the next replica.
190The default readiness budget is 60 seconds; set `deploy.healthTimeout`
191for a longer bounded wait. A failed wait stops the rollout with
192`Fly.ReplicaChecksNotPassing` and
193the last observed check names, statuses, and output. Later replicas
194remain unchanged; earlier updates are not automatically rolled back.
195The default rolling strategy updates in place, so a single replica can be
196unavailable while it updates. Set `deploy: { strategy: "bluegreen" }` to
197[prepare checked replacement Machines before retirement](/fly/compute/deployments).
198
199For rolling, `skipLaunch: true` creates or updates config without starting
200or checking it. By default, delete force-destroys and waits until gone.
201Setting `shutdown` or enabling blue/green instead cordons reachable
202predecessors, signals each with its own persisted shutdown policy, waits
203for it to stop, and verifies deletion. A new generation's shorter timeout
204must not shorten the old process's grace window.
205
206A raw image must handle signals, stop accepting work, and drain requests or jobs.
207These props do not install the Effect runtime in it. A genuinely unreachable
208host may require force-deleting an owned stateless predecessor once its
209replacement is ready. This cannot prove the old work drained. See the
210[deployment and recovery limits](/fly/compute/deployments).
211
212Alchemy uses native Machine leases. It reports contention rather than stealing
213a lease. These leases do not lock the whole App or serialize every first
214deployment. Serialize CI deployments to the same resource. LocalState is not
215a cross-process lock, and App deletion has no Machine-lease precondition.
216
217`autoDestroy: true` removes a Machine when its process exits. Blue/green requires
218a persistent process and rejects this option, explicit `skipLaunch`, attached
219volumes, and missing readiness checks. It reports unsupported settings rather
220than silently switching to rolling. Stop and suspend are supported through the
221[idle-capacity rules](/fly/compute/deployments#keep-idle-capacity-with-stop-or-suspend).
222
223## Service or Sprite
224
225Prefer a [`Service`](/fly/compute/services) when the program is
226Effect. A Service is effectful, supports bindings, and scales with
227`count`. It owns its App and addresses, and `api.url` is its public
228endpoint. Alchemy builds and pushes the image. Prefer a
229[`Sprite`](/fly/compute/sprites) when the sandbox can hibernate —
230no App, no Docker image.
231
232```typescript
233export default class Api extends Fly.Service<Api>()(
234 "Api",
235 { main: import.meta.url, region: "iad", count: 3, port: 3000 },
236 Effect.gen(function* () {
237 return {
238 fetch: Effect.succeed(HttpServerResponse.text("hello")),
239 };
240 }),
241) {}
242```
243
244## Where next
245
246- [Blue/green deployments](/fly/compute/deployments) — readiness, graceful shutdown, and recovery.
247
248- [Services](/fly/compute/services) — bundle an Effect program into
249 a Machine.
250- [Regions](/fly/compute/regions) — where a Machine lives.
251- [Volumes](/fly/data/volumes) — persistent disks.
252- [`Machine` reference](/providers/fly/machine) — every prop and
253 attribute.