Back to Blog
Tutorial7 min read2026-05-01

Docker Compose for Local Development: Multi-Service Setup

Use Docker Compose to run your entire multi-service application stack locally with a single command.

The Problem with "It Works Locally"

Modern applications rarely consist of a single service. A typical web app needs a backend API, a database, a cache, maybe a background worker. Getting all of these running consistently across a team is painful without the right tooling. Docker Compose solves this — it lets you define and run multi-container applications with a single docker compose up.

What Is Docker Compose?

Docker Compose uses a YAML file (docker-compose.yml) to define your application's services, networks, and volumes. With one command, it starts all services in the correct order, connected to the same network, with persistent volumes where needed.

Installing Docker Compose

Docker Compose v2 ships with Docker Desktop. On Linux, install the plugin:

sudo apt-get install docker-compose-plugin
docker compose version

A Real-World Example: Node.js + PostgreSQL + Redis

Let's build a docker-compose.yml for a backend API that uses PostgreSQL for storage and Redis for caching.

First, the Dockerfile for the API:

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

EXPOSE 3000
CMD ["npm", "run", "dev"]

Now the docker-compose.yml:

version: '3.9'

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://postgres:secret@db:5432/myapp
      REDIS_URL: redis://cache:6379
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:7-alpine
    volumes:
      - cache_data:/data

volumes:
  db_data:
  cache_data:

Key Concepts Explained

depends_on with health checksdepends_on: condition: service_healthy waits for PostgreSQL to be ready before starting the API. Without this, the API often crashes on startup because the database isn't accepting connections yet.

Named volumes (db_data, cache_data) — Data persists between docker compose down and docker compose up restarts. Without named volumes, your database is wiped every time you stop the stack.

Source code bind mount (. :/app) — Maps your local project directory into the container. Code changes are reflected immediately without rebuilding the image, enabling hot-reload development.

/app/node_modules anonymous volume — Prevents the host's node_modules from overwriting the container's. Essential on macOS/Windows where file system differences cause issues.

Common Commands

docker compose up              # start all services (foreground)
docker compose up -d           # start in detached (background) mode
docker compose logs -f api     # stream logs from the api service
docker compose exec api sh     # open a shell in the running api container
docker compose down            # stop and remove containers
docker compose down -v         # also remove named volumes (wipes data)
docker compose build           # rebuild images without starting
docker compose ps              # list running services and their ports

Adding a Worker Service

Extend the same stack with a background worker:

  worker:
    build: .
    command: node worker.js
    environment:
      DATABASE_URL: postgres://postgres:secret@db:5432/myapp
      REDIS_URL: redis://cache:6379
    depends_on:
      - db
      - cache

The worker shares the same network as the API and database automatically — no extra configuration needed.

From Local to Production with PandaStack

Docker Compose is a local development tool — it's not designed for production. When you're ready to go live, PandaStack handles each service separately: deploy your API and worker as Docker container deployments, provision a managed PostgreSQL or Redis database from the platform, and connect them via environment variables.

Install the CLI:

npm install -g @pandastack/cli
panda deploy --type container --repo your-org/api-repo

Managed databases on PandaStack (PostgreSQL, MySQL, Redis, MongoDB) are production-ready with automated backups and connection pooling. See [docs.pandastack.io](https://docs.pandastack.io) or log in at [dashboard.pandastack.io](https://dashboard.pandastack.io) to get started.

Ready to deploy?

Start free on PandaStack — no credit card required.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also