# ChatDev Docker Deployment and Containerization: Multi-Stage Setup Guide

> Deploy ChatDev locally with Docker Compose multi-stage builds. This guide simplifies containerization, separating Python and Node.js services for immediate development access.

- Repository: [OpenBMB/ChatDev](https://github.com/OpenBMB/ChatDev)
- Tags: how-to-guide
- Published: 2026-04-01

---

**Deploy ChatDev locally using Docker Compose with multi-stage builds that separate Python and Node.js services, exposing ports 6400 and 5173 for immediate development access.**

ChatDev by OpenBMB is packaged as a containerized multi-service application designed for both rapid development and production deployment. This guide explains how to deploy and containerize ChatDev using Docker's multi-stage build pattern to create lean runtime images while maintaining fast rebuilds during iterative development.

## Multi-Stage Backend Containerization

The backend service is defined in the repository root `Dockerfile` and uses Python 3.12 with the `uv` package manager for deterministic dependency resolution. The build process splits compilation from runtime to minimize the final image size.

### Builder Stage

The **builder** stage handles dependency resolution and compilation. It starts from `python:3.12-slim` and installs system compilers including `pkg-config`, `build-essential`, `python3-dev`, and `libcairo2-dev`. The `uv` tool is installed via `pip install uv`, then configured to create the virtual environment at `/opt/venv` using `UV_PROJECT_ENVIRONMENT=/opt/venv`. The stage copies [`pyproject.toml`](https://github.com/OpenBMB/ChatDev/blob/main/pyproject.toml) and `uv.lock` before running `uv sync --no-cache --frozen` to populate the virtual environment without network calls.

### Runtime Stage

The **runtime** stage starts from a fresh `python:3.12-slim` image to exclude build tools. It installs only the runtime library `libcairo2`, copies the pre-built virtual environment from the builder, and sets `PATH="/opt/venv/bin:${PATH}"`. The application source is copied into the image, Python output is set to unbuffered mode, and a non-root user named `appuser` is created for security. Port **6400** is exposed, and the container executes `python server_main.py` to start the FastAPI backend.

```dockerfile

# Example: Build only the runtime stage

docker build \
  --target runtime \
  -t chatdev-backend:latest \
  -f Dockerfile .

```

## Frontend Container Architecture

The frontend service defined in `frontend/Dockerfile` uses Node.js 24 Alpine for minimal footprint and separates dependency installation from source code to maximize cache efficiency.

### Dependency Caching Stage

The **deps** stage uses `node:24-alpine` as the base image. It copies `package*.json` files and executes `npm ci` (falling back to `npm install`) to generate the `node_modules` directory. This layer is cached independently of application code changes, ensuring dependencies only reinstall when package definitions change.

### Development Runtime Stage

The **dev** stage copies the cached `node_modules` and remaining source code, sets `NODE_ENV=development`, and exposes port **5173**. It runs `npm run dev -- --host` to start the Vite development server with hot-reload enabled and network binding.

## Docker Compose Orchestration

The [`compose.yml`](https://github.com/OpenBMB/ChatDev/blob/main/compose.yml) file orchestrates both services with volume mounts that enable live editing without image rebuilds.

- **backend**: Builds targeting the `runtime` stage, mounts the repository root (`.:/app`), publishes `6400:6400`, and loads environment variables from `.env` and `.env.docker`.
- **frontend**: Builds targeting the `dev` stage, mounts `./frontend:/app`, publishes `${FRONTEND_PORT:-5173}:5173`, and declares a service dependency on the backend.

This configuration allows the frontend Vite server to communicate with the backend via the internal Docker network using the service name `backend` as the hostname.

## Environment Configuration

Docker-specific defaults are stored in `.env.docker` and automatically loaded by Compose:

```text
BACKEND_BIND=0.0.0.0
FRONTEND_HOST=0.0.0.0
FRONTEND_PORT=5173
VITE_API_BASE_URL=http://backend:6400
CORS_ALLOW_ORIGINS=http://localhost:5173,http://127.0.0.1:5173

```

For local development, copy the example file to `.env` and adjust project-specific values:

```bash
cp .env.example .env

```

The `VITE_API_BASE_URL` variable ensures the frontend browser requests proxy correctly to the backend container named `backend` on port 6400.

## Quick Start Deployment

Run the complete ChatDev stack with these commands:

```bash

# 1. Copy environment configuration

cp .env.example .env

# 2. Build and launch both services

docker compose up --build

# 3. Access the application

#    Frontend: http://localhost:5173

#    Backend API: http://localhost:6400

```

Volume mounts (`.:/app` for backend and `./frontend:/app` for frontend) enable real-time code changes to reflect immediately in running containers, ideal for rapid iteration on the OpenBMB/ChatDev codebase.

## Production Build Strategies

For continuous integration pipelines or standalone testing, build specific components without Compose:

Run the backend image independently for integration testing:

```bash
docker run -d \
  --name chatdev-backend \
  -p 6400:6400 \
  --env-file .env.docker \
  chatdev-backend:latest

```

Force a frontend dependency refresh after modifying [`package.json`](https://github.com/OpenBMB/ChatDev/blob/main/package.json):

```bash
docker compose build frontend
docker compose up -d frontend

```

## Summary

- **Multi-stage builds** separate compilation dependencies from runtime libraries, reducing the backend image to approximately 30 MB.
- **Backend security** uses a dedicated `appuser` account with dropped privileges rather than running as root.
- **Frontend caching** isolates `node_modules` in a dedicated stage, preventing unnecessary reinstalls during source code edits.
- **Service networking** relies on Docker Compose DNS, with the frontend connecting to `http://backend:6400` via `VITE_API_BASE_URL`.
- **Live development** is supported through bind mounts that map host directories directly into containers without rebuilds.

## Frequently Asked Questions

### What ports does ChatDev expose in Docker?

The backend exposes port **6400** for the Python FastAPI server, while the frontend development server exposes port **5173** (configurable via `FRONTEND_PORT` environment variable). These are mapped to the host in [`compose.yml`](https://github.com/OpenBMB/ChatDev/blob/main/compose.yml) using `6400:6400` and `${FRONTEND_PORT:-5173}:5173` respectively.

### How do I rebuild the frontend after updating package.json?

Run `docker compose build frontend` to invalidate the cached **deps** stage and reinstall Node modules, then execute `docker compose up -d frontend` to restart the service with the updated dependencies. This ensures `node_modules` reflects changes to `package*.json` files.

### Why does the backend use a non-root user?

The `Dockerfile` creates an `appuser` account and switches to it with `USER appuser` before executing [`server_main.py`](https://github.com/OpenBMB/ChatDev/blob/main/server_main.py) as a security best practice. This limits potential damage from container escapes or compromised processes by removing root filesystem privileges from the running Python application.

### Can I run the ChatDev backend without the frontend container?

Yes. Build the backend image targeting the **runtime** stage, then run it standalone using `docker run` with port mapping `-p 6400:6400` and an environment file `--env-file .env.docker`. This is useful for API testing, backend development, or when serving the frontend through a separate reverse proxy or static hosting solution.