Skip to content
BoringStack
GitHub

Recipe: Add a service to Compose

4 min read

Verified 2026-05

Recipes

Add a containerized service to your local stack as an isolated overlay. The core stack stays light; opt-in tools get their own resource budgets.

20 min

Estimated duration

Compose

Engine

Opt-in

Overlay Model

Add a new container to the stack as an overlay. A WITH_<NAME>=1 flag turns it on without changing the base file. Same model the observability, GlitchTip, Bull Board, and Mailpit overlays use.

Worked example below: adding Meilisearch as an opt-in search engine, exposed on a dev hostname and behind Basic Auth in prod.

  • A working local stack.
  • Read Profiles & overlays for the convention ./dev.sh and compose-up.sh follow.
  1. Create the overlay file. In infra/compose/compose/:

    docker-compose.meilisearch.yml
    services:
    meilisearch:
    image: getmeili/meilisearch:v1.10
    restart: unless-stopped
    environment:
    MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:?MEILI_MASTER_KEY is required}
    MEILI_NO_ANALYTICS: "true"
    volumes:
    - meilisearch_data:/meili_data
    networks:
    - backend
    deploy:
    resources:
    limits:
    cpus: "${MEILI_LIMITS_CPUS:-0.5}"
    memory: ${MEILI_LIMITS_MEMORY:-512M}
    reservations:
    cpus: "${MEILI_RESERVATIONS_CPUS:-0.1}"
    memory: ${MEILI_RESERVATIONS_MEMORY:-128M}
    volumes:
    meilisearch_data:

    The env-var-with-default pattern matches the rest of the stack (see Resource limits).

  2. Wire the overlay into dev.sh. The orchestrator already understands WITH_<NAME>=1 flags. Add the file to the case block:

    Terminal window
    # in compose/dev.sh
    if [ "${WITH_MEILISEARCH:-0}" = "1" ]; then
    COMPOSE_FILES+=( "-f" "compose/docker-compose.meilisearch.yml" )
    fi
  3. Add a dev-only labels overlay if you want a friendly hostname. Mirror the pattern in docker-compose.development-labels.yml:

    docker-compose.meilisearch-dev-labels.yml
    services:
    meilisearch:
    labels:
    traefik.enable: "true"
    traefik.http.routers.meilisearch.rule: Host(`meilisearch.localhost`)
    traefik.http.services.meilisearch.loadbalancer.server.port: "7700"

    Add a parallel meilisearch-prod-labels.yml for HTTPS + Basic Auth in production, following the GlitchTip prod overlay as the reference shape.

  4. Document the new flag in compose/.env.example:

    Terminal window
    # Meilisearch overlay (WITH_MEILISEARCH=1)
    MEILI_MASTER_KEY=
  5. Boot it:

    Terminal window
    WITH_MEILISEARCH=1 ./scripts/compose-up.sh
  • docker compose ps shows the meilisearch container in the running list alongside the base stack.
  • The volume meilisearch_data exists: docker volume ls | grep meilisearch.
  • The dev URL responds: curl http://meilisearch.localhost/health.
  • Flags compose: WITH_MEILISEARCH=1 WITH_OBSERVABILITY=1 ./scripts/compose-up.sh brings up both overlays cleanly.
  • Stopping cleanly preserves data: ./scripts/compose-down.sh then re-up; the index is still there.
  • infra/compose/compose/docker-compose.meilisearch.yml: new (the service).
  • infra/compose/compose/docker-compose.meilisearch-dev-labels.yml: new (Traefik routing in dev).
  • infra/compose/compose/docker-compose.meilisearch-prod-labels.yml: new (HTTPS + BasicAuth in prod).
  • infra/compose/compose/dev.sh: one new if block for the WITH_MEILISEARCH=1 flag.
  • infra/compose/compose/.env.example: new env stanza.

No changes to docker-compose.yml. That’s the point of the overlay model: the base never grows, opt-in services live in their own files.