# How to Deploy Workerd Applications Using Containers: A Complete Guide

> Learn to deploy workerd applications using containers with this complete guide. Discover how to leverage Docker for sandboxed execution and secure outbound traffic.

- Repository: [Cloudflare/workerd](https://github.com/cloudflare/workerd)
- Tags: how-to-guide
- Published: 2026-03-18

---

**Workerd deploys applications inside Docker containers using a built-in `ContainerClient` that communicates with the Docker daemon via Unix sockets, enabling sandboxed execution with optional egress-proxy sidecars for secure outbound traffic.**

Deploying workerd applications using containers allows you to run each Durable Object or service inside its own isolated Docker container while maintaining Workerd's native compatibility flags and runtime semantics. The `cloudflare/workerd` repository ships with a native container client that manages the full container lifecycle directly from the Workerd binary.

## Understanding Workerd's Container Architecture

The container integration centers on the **ContainerClient** class, which implements the RPC interface used by the JSG `Container` object. This client translates Workerd's internal operations into Docker API calls, creating a seamless bridge between the Workerd runtime and container orchestration platforms.

### The ContainerClient Implementation

The core container logic resides in two primary source files:

- **[`src/workerd/server/container-client.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/server/container-client.h)** – Declares the `ContainerClient` class that handles the RPC interface and container state management.
- **`src/workerd/server/container-client.c++`** – Contains the actual Docker API implementation, including `dockerApiRequest` and lifecycle helpers for creating, starting, stopping, and destroying containers.

When Workerd initializes with container support enabled, it instantiates a `ContainerClient` that connects to the Docker daemon through a Unix socket (or TCP socket). The client exposes methods like `createContainer`, `startContainer`, and `listenTcp` that manage the sandboxed environment.

### Configuration and API Schemas

The container feature relies on Cap'n Proto schemas for type-safe communication:

- **`src/workerd/server/docker-api.capnp`** – Defines the Cap'n Proto schema for Docker HTTP API requests and responses used by the client.
- **`src/workerd/server/workerd.capnp`** – Contains the top-level configuration schema, including the `Worker::ContainerEngine` definition that enables the container engine block in your configuration.

## Configuring the Container Engine

Workerd parses container settings during the configuration phase and wires the client into the worker's execution path.

### Writing the Workerd Configuration

To enable containerized execution, add a `containerEngine` block to your Workerd configuration file. The following YAML maps to `Worker::ContainerEngine` in `src/workerd/server/workerd.capnp`:

```yaml
services:
  - name: my-app
    worker:
      modules:
        - name: worker
          esModule: embed "worker.mjs"
      compatibilityDate: "2024-01-01"
      containerEngine:
        localDocker:
          socketPath: "unix:/var/run/docker.sock"
          containerEgressInterceptorImage: "cloudflare/proxy-everything:main"

```

The `localDocker` variant is currently the only supported engine. The `socketPath` specifies the Docker daemon socket, while `containerEgressInterceptorImage` optionally defines an egress-proxy sidecar image for handling outbound HTTP traffic.

### Server Configuration Parsing

In `src/workerd/server/server.c++` (lines 4012-4830), the `Server::applyConfig` method reads the `containerEngineConf` from the parsed configuration. When the variant is `localDocker`, Workerd extracts the socket path and sidecar image settings, then initializes the `ContainerClient` for that worker. All subsequent I/O is routed through the container's network namespace.

## Building and Running Containerized Workerd Applications

Once configured, you can package Workerd itself as a container image or let Workerd spawn child containers dynamically.

### Creating the Docker Image

Build a container image that includes the Workerd binary and your configuration:

```dockerfile
FROM debian:bookworm-slim AS builder
RUN apt-get update && apt-get install -y libcapnp0.8 libkj0.9 libssl3 ca-certificates && rm -rf /var/lib/apt/lists/*

COPY workerd /usr/local/bin/workerd
COPY my-app.wd-test /etc/workerd/my-app.wd-test

ENTRYPOINT ["/usr/local/bin/workerd", "--config", "/etc/workerd/my-app.wd-test"]

```

Build and push the image:

```bash
docker build -t my-org/workerd-app:latest .
docker push my-org/workerd-app:latest

```

### Running with Docker Socket Access

To allow Workerd to spawn and manage containers, mount the Docker daemon socket when running the container:

```bash
docker run -d \
  --name workerd-runtime \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v $(pwd)/my-app.wd-test:/etc/workerd/my-app.wd-test \
  my-org/workerd-app:latest

```

Workerd reads the `containerEngine` stanza, contacts the Docker daemon via the mounted socket, and creates child containers for your workers dynamically. The `ContainerClient::createContainer` method builds the Docker "create" request, injecting the worker's environment variables and container name.

## Advanced: Egress Proxy Sidecars

For applications requiring controlled outbound access, Workerd supports running an egress-proxy sidecar container alongside the main worker container.

### Configuring the Sidecar

When `containerEgressInterceptorImage` is specified in the configuration, `ContainerClient::createSidecarContainer` (lines 1500-1550 of `container-client.c++`) launches a second container that listens on a dynamically allocated high port. The `setEgressHttp` RPC method routes all outbound HTTP/HTTPS traffic through this sidecar, providing "proxy-everything" functionality required for secure sandboxed egress.

The sidecar container runs in the same network namespace as the worker, with `ContainerClient::listenTcp` exposing the TCP port on the host that Workerd uses for inbound connections.

## Summary

- **Workerd's container support** is implemented through the `ContainerClient` class in `src/workerd/server/container-client.c++`, which communicates directly with the Docker daemon.
- **Configuration** occurs via the `containerEngine` block in `workerd.capnp` schemas, parsed by `Server::applyConfig` in `server.c++`.
- **Socket access** requires mounting `/var/run/docker.sock` into the Workerd container to enable container creation and management.
- **Egress control** is available through the optional `containerEgressInterceptorImage` setting, which launches a sidecar container via `createSidecarContainer`.
- **Networking** is handled dynamically, with `listenTcp` allocating host ports that forward traffic to the sandboxed container.

## Frequently Asked Questions

### How does Workerd communicate with the Docker daemon?

Workerd communicates with the Docker daemon through a Unix socket (or TCP socket) specified in the `socketPath` configuration field. The `ContainerClient` class in `src/workerd/server/container-client.c++` uses this socket to issue Docker API calls for container creation, lifecycle management, and networking setup.

### What is the purpose of the egress-proxy sidecar?

The egress-proxy sidecar provides controlled outbound HTTP/HTTPS access for sandboxed containers. When `containerEgressInterceptorImage` is configured, Workerd launches a secondary container via `createSidecarContainer` that intercepts all outbound traffic through the `setEgressHttp` RPC method, enabling secure proxy functionality without exposing the host network directly to the worker.

### Can I run Workerd containers on Kubernetes?

Yes. Since Workerd's container integration uses standard Docker API calls through the container runtime interface (CRI), you can deploy Workerd on Kubernetes by ensuring the pod has access to the container runtime socket. Mount the appropriate socket path (often `/var/run/docker.sock` or `/var/run/containerd/containerd.sock` depending on your Kubernetes setup) and configure the `socketPath` in your Workerd configuration accordingly.

### Where is the container engine configuration defined in the source code?

The container engine configuration is defined in `src/workerd/server/workerd.capnp` within the `Worker::ContainerEngine` Cap'n Proto struct. The runtime parsing logic resides in `src/workerd/server/server.c++` (lines 4012-4830), where `Server::applyConfig` extracts the `containerEngineConf` and initializes the `ContainerClient` for workers with container support enabled.