Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Docker Compose Build

Learn to build images using docker compose build for efficient multi-service development.

Focus: docker compose build images

Sponsored

You've built Dockerfiles by hand, run docker build a hundred times, and started containers with docker run. But as your project grows to include a database, a cache, and a background worker, those individual docker build commands become a chore: you need to remember the right context paths, tags, and dependencies for each service. docker compose build solves this by centralizing all your image building logic into a single docker-compose.yml file, letting you rebuild an entire multi-service stack with one command.

The problem this lesson solves

When developing a real-world application, you rarely have just one container. You might have a Python web API, a Redis cache, a PostgreSQL database, and a Celery worker. In a team environment, every developer needs to build the exact same images. Running docker build -t myapp-web . and docker build -t myapp-worker ./worker manually is error-prone and slow. You'll forget tags, mismatch base images, or build in the wrong order.

Docker Compose gives you a declarative way to define how each image is built. Instead of scripts or tribal knowledge, your build process lives in version control. docker compose build reads the build section of your services and executes the builds in the correct order, respecting dependencies like depends_on. This lesson will teach you to stop building images individually and start managing your builds as a unified workflow.

Core concept / mental model

Think of docker compose build as an orchestrated batch builder. Where docker build is a single hammer, docker compose build is a toolbox that contains many hammers and knows which one to use first.

What docker compose build does

  • Reads your docker-compose.yml (or compose.yaml) file.
  • For each service that has a build key, it runs docker build using the specified context, Dockerfile, and build arguments.
  • It builds images in the order defined by depends_on where possible, ensuring base images are ready before dependent services need them.
  • Tags images automatically using the pattern <project>_<service> (or your custom tags).

Project name is key

By default, Compose uses the directory name as the project name. So if your project folder is myapp, images will be named myapp_web, myapp_db, and so on. You can override this with -p flag or a name top-level key in your Compose file.

Pro tip: Use docker compose build --help to see all available flags. The --no-cache flag is your best friend when debugging stale builds.

How it works step by step

Let's break down the build process for a typical web app with a database.

1. Define services with build keys

In your docker-compose.yml, each service can have a build key instead of (or in addition to) an image key. The build key points to a directory containing a Dockerfile.

services:
  web:
    build: ./web
    ports:
      - "8000:8000"
  db:
    build: ./db
    environment:
      POSTGRES_PASSWORD: example

2. Run docker compose build

$ docker compose build
[+] Building 3.4s (12/12) FINISHED
 => [web internal] load build definition from Dockerfile           0.0s
 => [web internal] transfering dockerfile: 120B                    0.0s
 => [web] resolve docker.io/library/python:3.11-slim              0.2s
 => [web] CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]    0.1s
 => [db internal] load build definition from Dockerfile            0.0s
 => [db] FROM postgres:15-alpine                                  0.5s
...

Compose builds both images, tagging them automatically. You can see the built images with docker images:

$ docker images
REPOSITORY          TAG       IMAGE ID       CREATED          SIZE
myapp_web           latest    abc123def456   2 minutes ago    150MB
myapp_db            latest    def789abc012   2 minutes ago    200MB

Note: If a service has both build and image keys, the image tag is applied after building. This is useful for pushing to a registry.

Hands-on walkthrough

Let's build a practical example: a Python web app with a Redis cache.

Project structure

myapp/
├── docker-compose.yml
├── web/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── app.py
└── redis/
    └── Dockerfile

docker-compose.yml

version: "3.9"
services:
  web:
    build: ./web
    ports:
      - "5000:5000"
    depends_on:
      - cache
  cache:
    build: ./redis

web/Dockerfile

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

Build and run

$ cd myapp
$ docker compose build
$ docker compose up -d

This builds both images, then starts containers. Notice Compose built cache first because web depends on it.

Build with arguments

Sometimes you need to pass build-time variables, like a version number:

services:
  web:
    build:
      context: ./web
      args:
        APP_VERSION: "1.0.0"

Build with a specific argument:

$ docker compose build --build-arg APP_VERSION=2.0.0

Pro tip: Use .env files to keep build arguments out of your Compose file. Create a .env file with APP_VERSION=1.5.0 and reference it as ${APP_VERSION:-latest} in your Compose file.

Compare options / when to choose what

Feature docker build docker compose build
Single image ✅ Best ❌ Overkill
Multi-service app ❌ Manual orchestration ✅ Best
CI/CD pipeline ✅ Good for single service ✅ Good for full stack
Development workflow ❌ Repetitive ✅ One command rebuild
Custom network builds ❌ Manual network config ✅ Automatic
Layer caching across builds ✅ Same as docker build ✅ Same, plus shared cache

When to use each: - Use docker build for standalone images (e.g., a base image or a CLI tool). - Use docker compose build when your application involves multiple interconnected services.

Troubleshooting & edge cases

Dockerfile not found

$ docker compose build
service "web" failed to build: unable to prepare context: path "./web" not found

Fix: Ensure the build path is relative to the location of your Compose file, not your current working directory.

Unsupported Dockerfile name

If your Dockerfile isn't named Dockerfile, specify the filename:

services:
  web:
    build:
      context: ./web
      dockerfile: Dockerfile.dev

Build takes forever / no caching

If builds seem slow or don't use cache, ensure your .dockerignore file excludes unnecessary files (like node_modules, __pycache__, .git). Also check that files aren't changing on every build (e.g., timestamps in copied files).

Build succeeds but containers crash immediately

This is usually a runtime issue, not a build issue. Debug with:

$ docker compose logs
$ docker compose run web sh  # enter the container interactively

What you learned & what's next

In this lesson, you learned to: - Explain the core idea behind Build images with docker compose build. - Complete a practical exercise for Build images with docker compose build, including passing build arguments and understanding build order. - Connect Build images with docker compose build to the next lesson in the track.

You now know how to replace a dozen docker build commands with a single docker compose build call, saving time and reducing errors. Your team can share a single Compose file and rebuild the entire stack consistently.

What's next: The next lesson covers Using volumes with Docker Compose to persist data across container restarts. You'll learn how to add volumes to your Compose services, ensuring your database data survives rebuilds.

Practice recap

Create a new project folder with a docker-compose.yml that defines two services: app (a simple Python Flask app) and redis. Add a build key for each service pointing to subdirectories containing Dockerfiles. Run docker compose build and verify the images exist with docker images. Then add a build argument for APP_VERSION and rebuild with a different version.

Common mistakes

  • Forgetting to add a dockerignore file, causing the build context to include gigabytes of unnecessary files (like node_modules) and making builds extremely slow.
  • Expecting docker compose build to rebuild images when only the Compose file changes — it only rebuilds when the build context or Dockerfile changes.
  • Using build and image keys together without understanding that image becomes a tag after build, not a pull from a registry.
  • Assuming depends_on guarantees build order — it only guarantees container startup order. Use depends_on with condition: service_completed_successfully for strict build dependencies.

Variations

  1. Use docker compose build --parallel to build multiple services simultaneously when they have no interdependencies, reducing overall build time.
  2. Use docker compose up --build to combine build and start in one command — useful for rapid iteration during development.
  3. Use docker compose build --push to build and push images to a registry in one step, ideal for CI/CD pipelines.

Real-world use cases

  • A team of 5 developers uses docker compose build to ensure everyone builds exactly the same web API, worker, and database images from a shared Compose file.
  • A CI pipeline runs docker compose build --pull --no-cache to build production-ready images from scratch, then runs integration tests with docker compose up.
  • A Python ML project uses docker compose build to build a Jupyter notebook server and a GPU-accelerated training service, with custom build args for CUDA versions.

Key takeaways

  • docker compose build builds all images defined in your Compose file with a single command, respecting build order and dependencies.
  • Images are tagged automatically with the pattern <project>_<service>, but you can override with custom tags using the image key.
  • Use --no-cache and --pull flags for fresh builds in CI/CD pipelines or when debugging stale layers.
  • Always include a .dockerignore file to keep build contexts small and builds fast.
  • Combine docker compose build with docker compose up --build for a seamless build-and-run workflow in development.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.