Skip to main content
This guide walks through a full Docker Compose deployment of Hatchet, including PostgreSQL and RabbitMQ. If you only need a quick local instance, see the CLI quick start instead.

Prerequisites

  • Docker v24 or later
  • Docker Compose v2 or later (included with Docker Desktop)

Setup

1

Create your docker-compose.yml

Create a docker-compose.yml file with the following services:
docker-compose.yml
version: "3.8"
services:
  postgres:
    image: postgres:15.6
    command: postgres -c 'max_connections=1000'
    restart: always
    hostname: "postgres"
    environment:
      - POSTGRES_USER=hatchet
      - POSTGRES_PASSWORD=hatchet
      - POSTGRES_DB=hatchet
    ports:
      - "5435:5432"
    volumes:
      - hatchet_postgres_data:/var/lib/postgresql/data
    shm_size: 1g
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d hatchet -U hatchet"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 10s

  rabbitmq:
    image: "rabbitmq:4-management"
    hostname: "rabbitmq"
    ports:
      - "5673:5672"   # RabbitMQ AMQP
      - "15673:15672" # Management UI
    environment:
      RABBITMQ_DEFAULT_USER: "user"
      RABBITMQ_DEFAULT_PASS: "password"
    volumes:
      - "hatchet_rabbitmq_data:/var/lib/rabbitmq"
      - "hatchet_rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf"
    healthcheck:
      test: ["CMD", "rabbitmqctl", "status"]
      interval: 10s
      timeout: 10s
      retries: 5

  migration:
    image: ghcr.io/hatchet-dev/hatchet/hatchet-migrate:latest
    command: /hatchet/hatchet-migrate
    environment:
      DATABASE_URL: "postgres://hatchet:hatchet@postgres:5432/hatchet"
    depends_on:
      postgres:
        condition: service_healthy

  setup-config:
    image: ghcr.io/hatchet-dev/hatchet/hatchet-admin:latest
    command: /hatchet/hatchet-admin quickstart --skip certs --generated-config-dir /hatchet/config --overwrite=false
    environment:
      DATABASE_URL: "postgres://hatchet:hatchet@postgres:5432/hatchet"
      SERVER_MSGQUEUE_RABBITMQ_URL: amqp://user:password@rabbitmq:5672/
      SERVER_AUTH_COOKIE_DOMAIN: localhost:8080
      SERVER_AUTH_COOKIE_INSECURE: "t"
      SERVER_GRPC_BIND_ADDRESS: "0.0.0.0"
      SERVER_GRPC_INSECURE: "t"
      SERVER_GRPC_BROADCAST_ADDRESS: localhost:7077
      SERVER_DEFAULT_ENGINE_VERSION: "V1"
      SERVER_INTERNAL_CLIENT_INTERNAL_GRPC_BROADCAST_ADDRESS: hatchet-engine:7070
    volumes:
      - hatchet_certs:/hatchet/certs
      - hatchet_config:/hatchet/config
    depends_on:
      migration:
        condition: service_completed_successfully
      rabbitmq:
        condition: service_healthy
      postgres:
        condition: service_healthy

  hatchet-engine:
    image: ghcr.io/hatchet-dev/hatchet/hatchet-engine:latest
    command: /hatchet/hatchet-engine --config /hatchet/config
    restart: on-failure
    ports:
      - "7077:7070"
    environment:
      DATABASE_URL: "postgres://hatchet:hatchet@postgres:5432/hatchet"
      SERVER_GRPC_BIND_ADDRESS: "0.0.0.0"
      SERVER_GRPC_INSECURE: "t"
    volumes:
      - hatchet_certs:/hatchet/certs
      - hatchet_config:/hatchet/config
    depends_on:
      setup-config:
        condition: service_completed_successfully
      migration:
        condition: service_completed_successfully

  hatchet-dashboard:
    image: ghcr.io/hatchet-dev/hatchet/hatchet-dashboard:latest
    command: sh ./entrypoint.sh --config /hatchet/config
    restart: on-failure
    ports:
      - "8080:80"
    environment:
      DATABASE_URL: "postgres://hatchet:hatchet@postgres:5432/hatchet"
    volumes:
      - hatchet_certs:/hatchet/certs
      - hatchet_config:/hatchet/config
    depends_on:
      setup-config:
        condition: service_completed_successfully
      migration:
        condition: service_completed_successfully

volumes:
  hatchet_postgres_data:
  hatchet_rabbitmq_data:
  hatchet_rabbitmq.conf:
  hatchet_config:
  hatchet_certs:
Service summary:
ServiceImagePurposePort(s)
postgrespostgres:15.6Primary data store54355432
rabbitmqrabbitmq:4-managementMessage queue56735672, 1567315672
migrationghcr.io/.../hatchet-migrate:latestRuns database migrations (one-shot)
setup-configghcr.io/.../hatchet-admin:latestGenerates server config (one-shot)
hatchet-engineghcr.io/.../hatchet-engine:latestgRPC engine for task scheduling70777070
hatchet-dashboardghcr.io/.../hatchet-dashboard:latestREST API + web dashboard808080
2

Start the stack

Run the following command from the directory containing your docker-compose.yml:
docker compose up
Docker Compose will:
  1. Start PostgreSQL and RabbitMQ and wait for their health checks to pass
  2. Run database migrations
  3. Generate the server configuration
  4. Start the Hatchet engine and dashboard
Wait until you see log output from both hatchet-engine and hatchet-dashboard before proceeding.
3

Access the dashboard

Open http://localhost:8080 in your browser.Log in with the default credentials:
Email:    [email protected]
Password: Admin123!!
Change the default password immediately in any environment accessible from the internet.
4

Create an API token

You need an API token to connect your workers and application code to Hatchet. There are two ways to create one:From the dashboard:
  1. Log in and navigate to Settings.
  2. Click the API Tokens tab.
  3. Click Create API Token and copy the token.
From the CLI:
docker compose run --no-deps setup-config \
  /hatchet/hatchet-admin token create \
  --config /hatchet/config \
  --tenant-id 707d0855-80ab-4e1f-a156-f1c4546cbf52
Store the token securely — it will not be shown again.
5

Connect your SDK

Set the following environment variables in your worker and application processes:
export HATCHET_CLIENT_TOKEN="<your-api-token>"
export HATCHET_CLIENT_HOST_PORT="localhost:7077"
The SDK reads both variables automatically. See the quickstart for a full example of defining tasks and running workers.

Updating to the latest version

The compose file above uses latest tags. To pull the latest images:
docker compose pull
docker compose up -d

Running your worker inside Docker Compose

If your worker process also runs inside the same Docker Compose network, update the SERVER_GRPC_BROADCAST_ADDRESS in the setup-config service to use the container hostname instead of localhost:
docker-compose.yml
setup-config:
  environment:
    SERVER_GRPC_BROADCAST_ADDRESS: "hatchet-engine:7070"
Then make your worker service depend on the engine:
docker-compose.yml
worker:
  depends_on:
    hatchet-engine:
      condition: service_started
Changing SERVER_GRPC_BROADCAST_ADDRESS invalidates any previously issued API tokens. Re-run the token creation step after making this change.

Using Postgres as the message queue

RabbitMQ is optional. To use Postgres-backed messaging instead, set the following environment variable in the setup-config and hatchet-engine services, and remove all rabbitmq references from the compose file:
SERVER_MSGQUEUE_KIND: postgres

Optional: observability stack

The repository includes a separate docker-compose.infra.yml with Prometheus, Grafana, and HyperDX for metrics and tracing:
ServicePort
Prometheus90919090
Grafana30013000
HyperDX UI80818080
See the Prometheus metrics guide for configuration details.

Build docs developers (and LLMs) love