Docker Compose `services` Block Syntax Quick Reference

Author: Hanjie Chen | Published: 2025-01-16 | Updated: 2026-04-17

docker compose

compose.yml –> Detailed services Syntax

Services top-level elements | Docker Docs

container_name

1
2
# 指定 contianer name
container_name: web-app

If you do not specify container_name, Docker Compose will automatically generate a default container name in the format <project>_<service>_<number>.

e.g. test-website-articles-data-1

develop-watch

Use Compose Watch | Docker Docs

During development, when certain code changes, we often need to restart or rebuild the container so the changes take effect and we can inspect the result. But manually running docker compose down and then docker compose up is too cumbersome.

In this case, we can use the develop: watch field.

grammar

1
2
3
4
5
6
7
develp:
  watch:
    - path: project-source-path/
      target: container-destination-path
      action: 
      ignore:
        - ignore-path/

watch

  • All paths except ignore are based on the project path.
  • .dockerignore rules are applied automatically, and the .git directory is also ignored automatically.

action

  • sync copies changes from the project path to the container target path.
  • rebuild rebuilds a new image and replaces the original container.
  • sync+restart copies changes and restarts the container.

action can only be one of these three values and cannot be arbitrarily split or combined. For example, you cannot use restart by itself.

path and target

  • path: the host project path
  • target: the container path

If target is not specified, then the sync action will, by default, synchronize the host path to the same path inside the container.

ignore

It must be an array (list), even if there is only one element.

1
2
ignore:
  - logs/

wrong config

1
ignore: logs/

The paths in ignore are relative to the path parameter. For example, in my project:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
website
├── Readme.md
├── articles-sync
│   ├── Dockerfile
│   ├── ...
│   ├── logs
├── compose.yml
└── web-app
    ├── Dockerfile
    ├── ...
    ├── ...
    └── templates

If I want to ignore all files under the website/articles-sync/logs directory, then in YAML it should be:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
services:
  ...

  articles-sync:
    ...
    develop:
      watch:
        - path: ./articles-sync
          ignore:
            - logs/**
          action: rebuild

volumes:
  articles_data:

In fact, the Docker Compose Watch documentation barely explains the ignore relative path behavior, so I opened a PR to clarify it.

PR: Update file-watch.md: add ignore attribute path by hanjie-chen · Pull Request #21820 · docker/docs

compose watch VS. bind mounts

We can use bind mounts to share a host directory with a directory inside the container.

Similarly, we can use the compose watch field to detect source code changes and sync them into the container, while also using the ignore field and .dockerignore to control which files are watched.

However, the two can often coexist. For example, if I need to inspect all file changes in a directory inside the container in real time, I still need a bind mount, not just source code syncing.

start watch

We can enable watch mode with the following command:

1
docker compose up --watch

Or use:

1
docker compose watch

However, this command only outputs file-watching-related information and does not include detailed container runtime logs.

Note that the output of the first command is essentially still docker log, so if your SSH connection is disconnected unexpectedly, you can use the following command to view Docker logs in real time and get a similar effect:

1
docker compose logs -f

ports

docker documents: Services top-level elements | Docker Docs

We may want to expose a process inside the container to the host machine. In that case, we need to use the ports field.

grammar

1
2
ports:
  - "8080:5000"  # "<host-machine port>":"<container port>"

image & build

build: Compose Build Specification | Docker Docs

build

Used to specify how to build an image.

1
2
3
build:
  context: ./articles-sync
  dockerfile: Dockerfile
  • context: the location of the build context

  • dockerfile: the location of the Dockerfile. If the default name Dockerfile is used, this field can be omitted, and the whole section can be simplified to:

yaml build: ./articles-sync

By default, Docker Compose automatically names the built image in the format <project-name>_<service-name> (the project name is usually the current directory name).

If you need a custom image name, you can combine it with the image field:

1
2
build: ./articles-sync
image: articles-sync1.0

Tip

Although field order does not affect functionality, for readability and consistency we usually place build before image: logically, building first and naming afterward is more intuitive.

image

Used to specify an existing image (either built locally or pulled from a remote registry). Docker Compose will use this image directly to start the container instead of building a new one.

1
image: nginx

depends_on

depends_on is used to define dependency relationships between services and can control service startup order.

If service A specifies service B in its depends_on, then Docker Compose will ensure that service B starts first, and then service A starts.

1
2
3
nginx:
  depends_on:
    - web

healthcheck

Used to define container health checks. It allows Docker to periodically inspect the runtime state inside the container and determine the container's health status based on the result.

  • Automatically detect whether the application is running normally For example, a Flask application may already have crashed while the process is still running. By default, Docker will not detect this, but healthcheck can actively check for it.
  • Ensure dependent services are available For example, if web-app depends on articles-sync, you can use condition: service_healthy in the depends_on configuration of web-app so it waits until articles-sync becomes healthy before starting.
  • Enable smarter container management in Swarm or Compose When a service is unhealthy, Swarm may reschedule the container.

config

healthcheck mainly consists of the following parameters:

  • test: specifies the health check command to execute, usually a shell command or CMD form.
  • interval: the check interval (default 30s).
  • timeout: the timeout for the health check command (default 30s).
  • retries: how many failures are allowed before the container is considered unhealthy (default 3).
  • start_period: during this period after container startup, health checks will not be triggered. This is suitable for applications that start slowly.

example

Check whether a Flask application is running properly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
services:
  web-app:
    image: my-flask-app
    ports:
      - "5000:5000"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
  • test: uses curl to access http://localhost:5000/health; if the HTTP request fails, the container is considered unhealthy.
  • interval: 30s: checks once every 30 seconds.
  • timeout: 10s: if there is no response within 10 seconds, it counts as a failure.
  • retries: 3: after 3 consecutive failures, the container is marked as unhealthy.
  • start_period: 10s: during the first 10 seconds after the container starts, no health checks are performed, giving Flask time to start.

command

In a compose.yml file, the command field overrides the CMD startup command in the Dockerfile. For example, if we have the following compose.yml:

1
2
3
4
services:
  web-app:
    ...
    command: ["flask", "run", "--host=0.0.0.0", "--debug"]

And in the web-app Dockerfile it is written like this:

1
2
3
4
...

# 启动命令 (production)
CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "app:app"]

Then in the end, flask run will actually be used as the startup command. This is useful for development environment setup. For example, you can create a compose.dev.yml to override the command in the Dockerfile.

Custom fields

Fields starting with x- are treated by Docker as user-defined extensions. Compose completely ignores their contents, which makes them a great place to store YAML anchors.

For example, we can use x- and the & anchor to reuse some configuration, such as Docker log configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
x-logging: &default-logging
  driver: json-file
  options:
    max-size: "1m"
    max-file: "5"

services:
  articles-sync:
    ...
    logging: *default-logging
  ...
...