DevKit
← Back to Blog

Docker Compose for Beginners: From docker run to docker-compose.yml

7 min read

If you have ever run a docker run command with 10 flags and forgotten what half of them do the next day, Docker Compose is your solution. This guide walks you through converting messy run commands into clean, version-controlled YAML files.

Why Docker Compose?

A typical development setup might need a web server, a database, a cache layer, and a background worker. Running each as a separate docker run command means:

Docker Compose solves all of this with a single docker-compose.yml file. One command — docker compose up — brings your entire stack online.

Anatomy of a docker-compose.yml

version: "3.8"

services:
  web:
    image: node:18-alpine
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src
    environment:
      - NODE_ENV=development
    depends_on:
      - db

  db:
    image: postgres:15
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=myapp
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Converting docker run to Compose

Here is a real-world example. This docker run command:

docker run -d \
  --name myapp \
  -p 3000:3000 \
  -v ./data:/app/data \
  -e DATABASE_URL=postgres://localhost/db \
  --restart always \
  node:18-alpine npm start

Becomes this in docker-compose.yml:

services:
  myapp:
    image: node:18-alpine
    container_name: myapp
    ports:
      - "3000:3000"
    volumes:
      - ./data:/app/data
    environment:
      - DATABASE_URL=postgres://localhost/db
    restart: always
    command: npm start

The mapping is straightforward:

Common Patterns

Multi-service with networking

Services in the same Compose file can reach each other by service name. No need to manually create networks or use container IPs.

services:
  api:
    image: myapi:latest
    environment:
      - REDIS_URL=redis://cache:6379
  cache:
    image: redis:7-alpine

The api service connects to Redis using cache as the hostname — Docker Compose DNS handles it automatically.

Environment files

Instead of listing 20 environment variables inline, use an env file:

services:
  api:
    image: myapi:latest
    env_file:
      - .env.local

Health checks

services:
  db:
    image: postgres:15
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

Essential Commands

Tips

  1. Always pin image versions — use postgres:15 not postgres:latest
  2. Use named volumes for database data — anonymous volumes get deleted on down
  3. Add .dockerignore — keep node_modules and .git out of build context
  4. Use depends_on for startup ordering — but note it does not wait for readiness, only container start

Automate the conversion

Do not want to translate flags manually? Use our Docker Run to Compose tool — paste any docker run command and get a ready-to-use docker-compose.yml instantly.