Skip to main content
Chroma provides official Docker images for easy deployment. This guide covers single-instance Docker deployments using the official images.

Quick Start

The fastest way to get Chroma running with Docker:
docker run -p 8000:8000 ghcr.io/chroma-core/chroma:latest
This starts Chroma in ephemeral mode. Data will be lost when the container stops.

Basic Setup with Persistence

Create a docker-compose.yml file:
version: '3.9'

networks:
  net:
    driver: bridge

services:
  server:
    image: ghcr.io/chroma-core/chroma:latest
    environment:
      - IS_PERSISTENT=TRUE
    volumes:
      # Default configuration for persist_directory
      - chroma-data:/chroma/chroma/
    ports:
      - 8000:8000
    networks:
      - net

volumes:
  chroma-data:
    driver: local
Start the server:
docker-compose up -d

Production Configuration

For production deployments, use the configuration from the Chroma repository:
version: '3.9'

networks:
  net:
    driver: bridge

services:
  server:
    image: server
    build:
      context: .
      dockerfile: rust/Dockerfile
      target: cli
    volumes:
      # The default config specifies a persist_directory of /data
      - chroma-data:/data
    environment:
      - CHROMA_OPEN_TELEMETRY__ENDPOINT=${CHROMA_OPEN_TELEMETRY__ENDPOINT}
      - CHROMA_OPEN_TELEMETRY__SERVICE_NAME=${CHROMA_OPEN_TELEMETRY__SERVICE_NAME}
      - OTEL_EXPORTER_OTLP_HEADERS=${OTEL_EXPORTER_OTLP_HEADERS}
    restart: unless-stopped
    ports:
      - "8000:8000"
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:8000/api/v2/heartbeat" ]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - net

volumes:
  chroma-data:
    driver: local

Environment File

Create a .env file in the same directory:
# Observability (optional)
CHROMA_OPEN_TELEMETRY__ENDPOINT=
CHROMA_OPEN_TELEMETRY__SERVICE_NAME=chromadb
OTEL_EXPORTER_OTLP_HEADERS={}

Building from Source

Chroma’s official Dockerfile uses a multi-stage build process:

Dockerfile Overview

The Dockerfile (Dockerfile in the repository root) creates a production-ready image:
FROM python:3.11-slim-bookworm AS builder

# Install build dependencies
RUN apt-get update && apt-get install -y \
    build-essential gcc g++ cmake autoconf \
    python3-dev unzip curl make

# Install Rust toolchain
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y

# Install protobuf compiler
RUN curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v31.1/protoc-31.1-linux-x86_64.zip && \
    unzip -o protoc-*.zip -d /usr/local

# Build Chroma
COPY . /chroma
WORKDIR /chroma
RUN make -C idl proto_python
RUN python3 -m maturin build
RUN pip install --prefix="/install" --find-links target/wheels/ chromadb

# Final stage
FROM python:3.11-slim-bookworm AS final

COPY --from=builder /install /usr/local
COPY --from=builder /chroma /chroma

ENV CHROMA_HOST_ADDR="0.0.0.0"
ENV CHROMA_HOST_PORT=8000
ENV CHROMA_WORKERS=1
ENV CHROMA_LOG_CONFIG="chromadb/log_config.yml"
ENV CHROMA_TIMEOUT_KEEP_ALIVE=30

EXPOSE 8000

ENTRYPOINT ["/docker_entrypoint.sh"]
CMD [ "--workers ${CHROMA_WORKERS} --host ${CHROMA_HOST_ADDR} --port ${CHROMA_HOST_PORT} --proxy-headers --reload --log-config ${CHROMA_LOG_CONFIG} --timeout-keep-alive ${CHROMA_TIMEOUT_KEEP_ALIVE}"]

Build Custom Image

# Build the image
docker build -t my-chroma:latest .

# Run the custom image
docker run -p 8000:8000 -v chroma-data:/chroma/chroma my-chroma:latest

Build Arguments

# Rebuild hnswlib from source (useful for specific CPU architectures)
docker build --build-arg REBUILD_HNSWLIB=true -t my-chroma:latest .

# Specify protobuf version
docker build --build-arg PROTOC_VERSION=31.1 -t my-chroma:latest .

Environment Variables

Server Configuration

VariableDefaultDescription
CHROMA_HOST_ADDR0.0.0.0Host address to bind to
CHROMA_HOST_PORT8000Port to listen on
CHROMA_WORKERS1Number of worker processes
CHROMA_LOG_CONFIGchromadb/log_config.ymlPath to logging configuration
CHROMA_TIMEOUT_KEEP_ALIVE30Keep-alive timeout in seconds
CHROMA_SERVER_NOFILE65536Maximum number of open files

Persistence

VariableDefaultDescription
IS_PERSISTENTFALSEEnable persistent storage
PERSIST_DIRECTORY./chromaDirectory for persistent data

Authentication

services:
  server:
    image: ghcr.io/chroma-core/chroma:latest
    environment:
      - IS_PERSISTENT=TRUE
      - CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.basic_authn.BasicAuthenticationServerProvider
      - CHROMA_SERVER_AUTHN_CREDENTIALS_FILE=/chroma/auth/credentials.htpasswd
    volumes:
      - ./credentials.htpasswd:/chroma/auth/credentials.htpasswd
      - chroma-data:/chroma/chroma/
See the Authentication guide for more details.

Observability

services:
  server:
    image: ghcr.io/chroma-core/chroma:latest
    environment:
      - IS_PERSISTENT=TRUE
      - CHROMA_OTEL_COLLECTION_ENDPOINT=http://jaeger:4317
      - CHROMA_OTEL_SERVICE_NAME=chromadb
      - OTEL_EXPORTER_OTLP_HEADERS={"x-api-key":"your-key"}

Volume Mounts and Persistence

Data Directory

The default persist directory depends on the configuration: Python-based image (ghcr.io/chroma-core/chroma):
volumes:
  - chroma-data:/chroma/chroma/
Rust-based image (built from source):
volumes:
  - chroma-data:/data

Custom Persist Directory

services:
  server:
    image: ghcr.io/chroma-core/chroma:latest
    environment:
      - IS_PERSISTENT=TRUE
      - PERSIST_DIRECTORY=/custom/path
    volumes:
      - chroma-data:/custom/path

Backup Data

# Create a backup
docker run --rm -v chroma-data:/data -v $(pwd):/backup \
  ubuntu tar czf /backup/chroma-backup.tar.gz -C /data .

# Restore from backup
docker run --rm -v chroma-data:/data -v $(pwd):/backup \
  ubuntu tar xzf /backup/chroma-backup.tar.gz -C /data

Docker Commands

Basic Operations

# Start Chroma
docker-compose up -d

# View logs
docker-compose logs -f

# Stop Chroma
docker-compose down

# Stop and remove volumes
docker-compose down -v

Maintenance

# Check health
curl http://localhost:8000/api/v2/heartbeat

# View running containers
docker-compose ps

# Restart the service
docker-compose restart server

# Update to latest image
docker-compose pull
docker-compose up -d

Healthcheck

The official configuration includes a healthcheck:
healthcheck:
  test: [ "CMD", "curl", "-f", "http://localhost:8000/api/v2/heartbeat" ]
  interval: 30s
  timeout: 10s
  retries: 3
Check health status:
docker inspect --format='{{.State.Health.Status}}' <container-id>

Restart Policies

Configured restart behavior:
restart: unless-stopped  # Options: "no", "always", "on-failure", "unless-stopped"

Networking

Custom Network

networks:
  chroma-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16

services:
  server:
    networks:
      chroma-network:
        ipv4_address: 172.28.0.2

Expose to External Network

services:
  server:
    ports:
      - "0.0.0.0:8000:8000"  # Expose on all interfaces
      # or
      - "127.0.0.1:8000:8000"  # Localhost only

Entrypoint Script

The Docker entrypoint (/docker_entrypoint.sh) handles service startup:
#!/bin/bash
set -e

export IS_PERSISTENT=1
export CHROMA_SERVER_NOFILE=${CHROMA_SERVER_NOFILE:-65536}
args="$@"

if [[ $args =~ ^uvicorn.* ]]; then
    exec $(eval echo "$args")
else
    exec uvicorn chromadb.app:app $(eval echo "$args")
fi

Troubleshooting

Container Fails to Start

# Check logs
docker-compose logs server

# Check if port is already in use
lsof -i :8000

# Verify volume permissions
docker-compose exec server ls -la /chroma/chroma

Data Not Persisting

Verify IS_PERSISTENT=TRUE is set and volume is mounted:
docker-compose exec server env | grep PERSISTENT
docker volume inspect <volume-name>

Performance Issues

Increase worker count for better concurrency:
environment:
  - CHROMA_WORKERS=4

Next Steps

Configuration

Learn about advanced configuration options

Authentication

Set up authentication and authorization

Kubernetes

Scale to Kubernetes for production

Observability

Monitor your Chroma deployment

Build docs developers (and LLMs) love