> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/calcom/cal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Configuration

> Comprehensive Docker and Docker Compose setup guide for Cal.com

This guide covers Docker-specific configuration, customization, and best practices for deploying Cal.com with Docker and Docker Compose.

## Overview

Cal.com provides official Docker images and Docker Compose configurations for easy deployment:

* **Docker Hub**: `calcom/cal.com`
* **Scarf Registry**: `calcom.docker.scarf.sh/calcom/cal.com` (default, for metrics)
* **GitHub**: Source Dockerfiles in the main repository

<Info>
  **Support Policy**: Cal.com maintains official Docker configurations, but users are responsible for their Docker-based installations. Community support is available via GitHub Discussions.
</Info>

## Docker Compose Services

The default `docker-compose.yml` includes multiple services:

### Service Architecture

```yaml theme={null}
services:
  database      # PostgreSQL database
  redis         # Redis cache and queues
  calcom        # Main web application
  calcom-api    # API v2 service
  studio        # Prisma Studio (optional)
```

### Database Service

```yaml theme={null}
database:
  container_name: database
  image: postgres
  restart: always
  volumes:
    - database-data:/var/lib/postgresql
  environment:
    - POSTGRES_USER=unicorn_user
    - POSTGRES_PASSWORD=magical_password
    - POSTGRES_DB=calendso
  networks:
    - stack
```

<Warning>
  **Change default credentials in production!**

  ```yaml theme={null}
  environment:
    - POSTGRES_USER=${POSTGRES_USER}
    - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    - POSTGRES_DB=calendso
  ```
</Warning>

### Redis Service

```yaml theme={null}
redis:
  container_name: redis
  image: redis:latest
  restart: always
  volumes:
    - redis-data:/data
  networks:
    - stack
  ports:
    - "${REDIS_PORT:-6379}:6379"
```

Redis is used for:

* Caching
* Job queues
* Session storage
* Rate limiting

### Cal.com Web Service

```yaml theme={null}
calcom:
  image: calcom.docker.scarf.sh/calcom/cal.com
  build:
    context: .
    dockerfile: Dockerfile
    args:
      NEXT_PUBLIC_WEBAPP_URL: ${NEXT_PUBLIC_WEBAPP_URL}
      NEXT_PUBLIC_LICENSE_CONSENT: ${NEXT_PUBLIC_LICENSE_CONSENT}
      NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
      CALENDSO_ENCRYPTION_KEY: ${CALENDSO_ENCRYPTION_KEY}
      DATABASE_URL: ${DATABASE_URL}
  restart: always
  networks:
    - stack
  ports:
    - 3000:3000
  env_file: .env
  environment:
    - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DATABASE_HOST}/${POSTGRES_DB}
  depends_on:
    - database
```

### API v2 Service

```yaml theme={null}
calcom-api:
  container_name: calcom-api
  build:
    context: .
    dockerfile: apps/api/v2/Dockerfile
    args:
      DATABASE_URL: ${DATABASE_URL}
  restart: always
  networks:
    - stack
  ports:
    - "${API_PORT:-80}:${API_PORT:-80}"
  env_file: .env
  environment:
    - API_PORT=${API_PORT:-80}
    - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DATABASE_HOST}/${POSTGRES_DB}
    - NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
    - REDIS_URL=${REDIS_URL}
  depends_on:
    - database
    - redis
```

### Prisma Studio (Development)

```yaml theme={null}
studio:
  image: calcom.docker.scarf.sh/calcom/cal.com
  restart: always
  networks:
    - stack
  ports:
    - 5555:5555
  env_file: .env
  environment:
    - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DATABASE_HOST}/${POSTGRES_DB}
  depends_on:
    - database
  command:
    - npx
    - prisma
    - studio
```

<Warning>
  **Remove or comment out Prisma Studio in production** to prevent unauthorized database access.
</Warning>

## Dockerfile Deep Dive

### Main Application Dockerfile

The Cal.com Dockerfile uses multi-stage builds:

#### Stage 1: Builder

```dockerfile theme={null}
FROM --platform=$BUILDPLATFORM node:20 AS builder

WORKDIR /calcom

# Build arguments
ARG NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000
ARG NEXTAUTH_SECRET=secret
ARG CALENDSO_ENCRYPTION_KEY=secret
ARG DATABASE_URL
ARG MAX_OLD_SPACE_SIZE=6144

# Environment variables for build
ENV NEXT_PUBLIC_WEBAPP_URL=http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER \
    NODE_OPTIONS=--max-old-space-size=${MAX_OLD_SPACE_SIZE} \
    BUILD_STANDALONE=true

# Copy source and build
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn ./.yarn
COPY apps/web ./apps/web
COPY packages ./packages

RUN yarn install
RUN yarn workspace @calcom/web run build
```

<Note>
  `NEXT_PUBLIC_WEBAPP_URL` is set to a placeholder during build and replaced at runtime by `start.sh` script.
</Note>

#### Stage 2: Builder-Two

```dockerfile theme={null}
FROM node:20 AS builder-two

WORKDIR /calcom
ARG NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000

ENV NODE_ENV=production

# Copy artifacts from builder
COPY --from=builder /calcom/yarn.lock ./yarn.lock
COPY --from=builder /calcom/node_modules ./node_modules
COPY --from=builder /calcom/packages ./packages
COPY --from=builder /calcom/apps/web ./apps/web

# Replace placeholder with actual URL
RUN scripts/replace-placeholder.sh http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER ${NEXT_PUBLIC_WEBAPP_URL}
```

#### Stage 3: Runner

```dockerfile theme={null}
FROM node:20 AS runner

WORKDIR /calcom

# Install utilities
RUN apt-get update && \
    apt-get install -y --no-install-recommends netcat-openbsd wget && \
    rm -rf /var/lib/apt/lists/*

COPY --from=builder-two /calcom ./

ENV NODE_ENV=production
EXPOSE 3000

# Health check
HEALTHCHECK --interval=30s --timeout=30s --retries=5 \
  CMD wget --spider http://localhost:3000 || exit 1

CMD ["/calcom/scripts/start.sh"]
```

### API v2 Dockerfile

```dockerfile theme={null}
FROM node:20-alpine AS build

ARG DATABASE_DIRECT_URL
ARG DATABASE_URL

WORKDIR /calcom

ENV NODE_ENV="production"
ENV NODE_OPTIONS="--max-old-space-size=8192"
ENV DATABASE_URL=${DATABASE_URL}

COPY . .

RUN yarn install
RUN yarn workspace @calcom/api-v2 run generate-schemas
RUN yarn workspace @calcom/api-v2 run build:docker
RUN yarn workspace @calcom/api-v2 run build

EXPOSE 80

CMD ["yarn", "workspace", "@calcom/api-v2", "start:prod"]
```

## Environment Variables

### Runtime Variables

These must be set in your `.env` file:

```bash theme={null}
# Database
DATABASE_URL="postgresql://unicorn_user:magical_password@database:5432/calendso"
DATABASE_HOST="database"
POSTGRES_USER="unicorn_user"
POSTGRES_PASSWORD="magical_password"
POSTGRES_DB="calendso"

# Redis
REDIS_URL="redis://redis:6379"
REDIS_PORT=6379

# Application
NEXT_PUBLIC_WEBAPP_URL="http://localhost:3000"
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="your-secret-here"
CALENDSO_ENCRYPTION_KEY="your-encryption-key"

# VAPID (Push Notifications)
NEXT_PUBLIC_VAPID_PUBLIC_KEY="your-public-key"
VAPID_PRIVATE_KEY="your-private-key"

# API v2
API_PORT=80
API_URL="http://calcom-api:80"
NEXT_PUBLIC_API_V2_URL="http://localhost:5555/api/v2"

# License (optional)
CALCOM_LICENSE_KEY="your-license-key"
```

### Build-time Arguments

For custom builds, pass these arguments:

```bash theme={null}
docker build \
  --build-arg NEXT_PUBLIC_WEBAPP_URL=https://cal.yourdomain.com \
  --build-arg NEXTAUTH_SECRET=$(openssl rand -base64 32) \
  --build-arg CALENDSO_ENCRYPTION_KEY=$(openssl rand -base64 24) \
  --build-arg DATABASE_URL=$DATABASE_URL \
  --build-arg MAX_OLD_SPACE_SIZE=8192 \
  --build-arg CALCOM_TELEMETRY_DISABLED=1 \
  -t calcom-custom:latest .
```

## Startup Process

The `scripts/start.sh` handles initialization:

```bash theme={null}
#!/bin/sh
set -x

# Replace build-time URL with runtime URL if different
scripts/replace-placeholder.sh "$BUILT_NEXT_PUBLIC_WEBAPP_URL" "$NEXT_PUBLIC_WEBAPP_URL"

# Wait for database
scripts/wait-for-it.sh ${DATABASE_HOST} -- echo "database is up"

# Run migrations
npx prisma migrate deploy --schema /calcom/packages/prisma/schema.prisma

# Seed app store
npx ts-node --transpile-only /calcom/scripts/seed-app-store.ts

# Start application
yarn start
```

### Initialization Steps

1. **URL Replacement**: Updates static files if `NEXT_PUBLIC_WEBAPP_URL` changed
2. **Database Wait**: Ensures PostgreSQL is ready
3. **Migrations**: Applies pending database migrations
4. **App Store Seed**: Syncs app metadata
5. **Application Start**: Launches Next.js server

<Note>
  Migrations run automatically on every container start. This is safe and idempotent.
</Note>

## Docker Compose Usage

### Running Services

```bash theme={null}
# All services (database + redis + calcom + api + studio)
docker compose up -d

# Web application only (requires external database)
docker compose up -d calcom

# Web + API (requires external database and redis)
docker compose up -d calcom calcom-api

# With Prisma Studio
docker compose up -d calcom studio

# View logs
docker compose logs -f calcom

# Stop services
docker compose down

# Stop and remove volumes (⚠️ deletes data)
docker compose down -v
```

### Updating Images

```bash theme={null}
# Pull latest images
docker compose pull

# Rebuild custom images
docker compose build --no-cache

# Restart with new images
docker compose up -d
```

### Scaling Services

```bash theme={null}
# Run multiple Cal.com instances
docker compose up -d --scale calcom=3

# Requires load balancer configuration
```

## Custom Docker Builds

### Building from Source

```bash theme={null}
# Clone repository
git clone https://github.com/calcom/cal.com.git
cd cal.com

# Start database for build
docker compose up -d database

# Build image
DOCKER_BUILDKIT=0 docker compose build calcom

# Run custom image
docker compose up -d
```

<Warning>
  `DOCKER_BUILDKIT=0` is required to enable network bridge during build. This limitation may be removed in future versions.
</Warning>

### Custom Dockerfile

Create a custom Dockerfile extending the base image:

```dockerfile theme={null}
FROM calcom/cal.com:latest

# Add custom scripts
COPY ./custom-scripts /calcom/custom-scripts
RUN chmod +x /calcom/custom-scripts/*

# Add custom dependencies
RUN yarn add custom-package

# Override start command
CMD ["/calcom/custom-scripts/start.sh"]
```

### Multi-platform Builds

```bash theme={null}
# Build for multiple architectures
docker buildx create --use
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t calcom-custom:latest \
  --push .
```

## ARM Architecture

### ARM Images

For Apple Silicon, Raspberry Pi, and ARM servers:

```bash theme={null}
# Pull ARM-specific image
docker pull calcom/cal.com:v5.6.19-arm

# Update docker-compose.yml
services:
  calcom:
    image: calcom/cal.com:v5.6.19-arm
```

### Building for ARM

```bash theme={null}
docker build --platform linux/arm64 -t calcom-arm:latest .
```

## Volumes and Persistence

### Default Volumes

```yaml theme={null}
volumes:
  database-data:    # PostgreSQL data
  redis-data:       # Redis persistence
```

### Backup Volumes

```bash theme={null}
# Backup database volume
docker run --rm \
  -v cal_database-data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/database-backup.tar.gz -C /data .

# Restore database volume
docker run --rm \
  -v cal_database-data:/data \
  -v $(pwd):/backup \
  alpine tar xzf /backup/database-backup.tar.gz -C /data
```

### Inspect Volumes

```bash theme={null}
# List volumes
docker volume ls

# Inspect volume
docker volume inspect cal_database-data

# Remove unused volumes
docker volume prune
```

## Networks

### Default Network

```yaml theme={null}
networks:
  stack:
    name: stack
    external: false
```

All services communicate on the `stack` network.

### Custom Networks

```yaml theme={null}
networks:
  frontend:
    name: frontend
  backend:
    name: backend

services:
  calcom:
    networks:
      - frontend
      - backend
  
  database:
    networks:
      - backend
```

## Health Checks

### Built-in Health Check

The Dockerfile includes automatic health monitoring:

```dockerfile theme={null}
HEALTHCHECK --interval=30s --timeout=30s --retries=5 \
  CMD wget --spider http://localhost:3000 || exit 1
```

### Custom Health Checks

```yaml theme={null}
services:
  calcom:
    healthcheck:
      test: ["CMD", "wget", "--spider", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
```

### Check Health Status

```bash theme={null}
# View health status
docker ps

# Inspect health
docker inspect --format='{{.State.Health.Status}}' calcom

# View health logs
docker inspect --format='{{json .State.Health}}' calcom | jq
```

## Production Optimizations

### Resource Limits

```yaml theme={null}
services:
  calcom:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '1'
          memory: 2G
```

### Restart Policies

```yaml theme={null}
services:
  calcom:
    restart: unless-stopped  # or 'always', 'on-failure'
```

### Logging Configuration

```yaml theme={null}
services:
  calcom:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
```

### Read-only Root Filesystem

```yaml theme={null}
services:
  calcom:
    read_only: true
    tmpfs:
      - /tmp
      - /calcom/.next/cache
```

## Troubleshooting

### View Logs

```bash theme={null}
# All services
docker compose logs

# Specific service
docker compose logs calcom

# Follow logs
docker compose logs -f calcom

# Last 100 lines
docker compose logs --tail=100 calcom
```

### Container Shell Access

```bash theme={null}
# Access running container
docker exec -it calcom sh

# Run one-off command
docker compose run --rm calcom sh
```

### Database Connection Issues

```bash theme={null}
# Test database from container
docker exec calcom wget --spider database:5432 || echo "Cannot reach database"

# Check database logs
docker compose logs database

# Test connection string
docker exec calcom npx prisma db pull --schema /calcom/packages/prisma/schema.prisma
```

### Port Conflicts

```
Error: Bind for 0.0.0.0:3000 failed: port is already allocated
```

**Solution:** Change port mapping:

```yaml theme={null}
ports:
  - "3001:3000"  # Host:Container
```

### Out of Memory

```
JavaScript heap out of memory
```

**Solution:** Increase memory:

```yaml theme={null}
environment:
  - NODE_OPTIONS=--max-old-space-size=8192
```

### Migration Failures

```bash theme={null}
# Check migration status
docker exec calcom npx prisma migrate status \
  --schema /calcom/packages/prisma/schema.prisma

# Manual migration
docker exec calcom npx prisma migrate deploy \
  --schema /calcom/packages/prisma/schema.prisma
```

## Security Best Practices

### Secret Management

```yaml theme={null}
# Use Docker secrets (Swarm mode)
secrets:
  db_password:
    file: ./secrets/db_password.txt

services:
  calcom:
    secrets:
      - db_password
    environment:
      - DATABASE_URL=postgresql://user:file:///run/secrets/db_password@db:5432/calendso
```

### Non-root User

Modify Dockerfile to run as non-root:

```dockerfile theme={null}
RUN addgroup -g 1001 calcom && \
    adduser -D -u 1001 -G calcom calcom

USER calcom
```

### Network Isolation

```yaml theme={null}
networks:
  frontend:
    internal: false
  backend:
    internal: true  # No external access
```

### Remove Development Tools

```yaml theme={null}
# Don't expose Prisma Studio in production
services:
  studio:
    profiles:
      - development

# Run only production profile
# docker compose --profile production up -d
```

## Monitoring and Observability

### Prometheus Metrics

Expose metrics endpoint:

```yaml theme={null}
services:
  calcom:
    labels:
      prometheus.scrape: "true"
      prometheus.port: "3000"
      prometheus.path: "/api/metrics"
```

### Container Stats

```bash theme={null}
# Real-time stats
docker stats calcom

# All containers
docker compose stats
```

## Production Checklist

* [ ] Change default database credentials
* [ ] Generate strong secrets (`NEXTAUTH_SECRET`, `CALENDSO_ENCRYPTION_KEY`)
* [ ] Generate VAPID keys for push notifications
* [ ] Remove or secure Prisma Studio service
* [ ] Configure proper `NEXT_PUBLIC_WEBAPP_URL`
* [ ] Set up external database or configure backups
* [ ] Configure Redis persistence
* [ ] Set resource limits and restart policies
* [ ] Configure logging rotation
* [ ] Enable health checks
* [ ] Use secrets management (not .env file)
* [ ] Set up reverse proxy (Nginx, Traefik, Caddy)
* [ ] Configure SSL certificates
* [ ] Test backup and restore procedures
* [ ] Monitor container health and logs
* [ ] Document custom configurations

## Next Steps

* Configure [Environment Variables](/self-hosting/configuration)
* Set up [Database](/self-hosting/database) with connection pooling
* Review [Deployment](/self-hosting/deployment) for orchestration options
