1---
2title: Docker
3description: Images, containers, networks, and volumes as Stack resources, driven through your active Docker CLI context.
4---
5
6The Docker provider manages images, containers, networks, and
7volumes by shelling out to the `docker` CLI's active context —
8Docker Desktop, a remote or SSH context, a CI daemon. There is no
9daemon API client and no credentials of its own, and the resources
10live in the same Stack as your cloud resources. It is separate from
11`Cloudflare.Container`; registry image references are the boundary
12between Docker-managed images and cloud container platforms.
13
14New here? [Set up Docker](/docker/setup) first.
15
16## Resources
17
18`RemoteImage`, `Network`, `Volume`, and `Container` compose into a
19local service — here, Postgres with a named volume, a network
20alias, a published port, and a healthcheck:
21
22```typescript
23export default Alchemy.Stack(
24 "DockerPostgresExample",
25 {
26 providers: Layer.merge(Docker.providers(), Alchemy.RandomProvider()),
27 state: Alchemy.localState(),
28 },
29 Effect.gen(function* () {
30 const password = yield* Alchemy.makeRandom("PostgresPassword", {
31 bytes: 16,
32 });
33
34 const image = yield* Docker.RemoteImage("postgres-image", {
35 name: "postgres",
36 tag: "18-alpine",
37 alwaysPull: false,
38 });
39 const network = yield* Docker.Network("app-network");
40 const data = yield* Docker.Volume("postgres-data");
41
42 const postgres = yield* Docker.Container("postgres", {
43 name: "alchemy-example-postgres",
44 image,
45 environment: {
46 POSTGRES_DB: "app",
47 POSTGRES_USER: "alchemy",
48 POSTGRES_PASSWORD: password,
49 },
50 ports: [{ external: 15432, internal: 5432 }],
51 volumes: [
52 { hostPath: data.name, containerPath: "/var/lib/postgresql/data" },
53 ],
54 networks: [{ name: network.name, aliases: ["postgres"] }],
55 healthcheck: {
56 cmd: ["CMD-SHELL", "pg_isready -U alchemy -d app"],
57 interval: "5 seconds",
58 timeout: "5 seconds",
59 retries: 10,
60 },
61 start: true,
62 });
63 return { container: postgres.name, hostPort: postgres.ports };
64 }),
65);
66```
67
68`Container` accepts the image resource directly, `alwaysPull: false`
69pins the pulled tag so re-deploys are no-ops, and environment values
70accept `Redacted` secrets — they are passed via process env, never
71on the CLI. [Run local services](/docker/local-services) walks
72through this composition.
73
74`Image` builds from a Dockerfile:
75
76```typescript
77const image = yield* Docker.Image("app", {
78 name: "my-app",
79 tag: "latest",
80 build: {
81 context: "./app",
82 dockerfile: "Dockerfile",
83 args: { NODE_ENV: "production" },
84 },
85});
86```
87
88The build *is* the diff: `diff` runs `docker build` and compares the
89resulting `imageId` against the last deploy, and the result is
90memoized so plan + deploy build once — see
91[Build and push an image](/docker/build-and-push) for tagging and
92pushing to a registry.
93
94`Docker.inspectContainer(name)` reads live runtime details for any
95container by name, including the bound host ports.
96
97:::caution
98Most prop changes on `Network`, `Volume`, and `Container` are
99**replacements** (delete-first) — the old resource is removed before
100the new one is created. And a same-name pre-existing container,
101network, or volume without alchemy labels surfaces as `Unowned`: the
102deploy fails with `OwnedBySomeoneElse` until you opt in with
103`.pipe(adopt(true))` or `--adopt`.
104:::
105
106## Compose with your cloud
107
108[ECS](/aws/compute/ecs) Tasks build their image with your local
109Docker — the AWS provider layers the same Docker service — and
110[Cloudflare Containers](/cloudflare/compute/containers) bring your
111own image by consuming the registry reference you push from
112[Build and push an image](/docker/build-and-push). By contrast,
113[MicroVMs](/aws/compute/microvms) build server-side on AWS and need
114no local Docker at all.
115
116## Reference
117
118[Container](/providers/docker/container) ·
119[Image](/providers/docker/image) ·
120[Network](/providers/docker/network) ·
121[RemoteImage](/providers/docker/remoteimage) ·
122[Volume](/providers/docker/volume)