DEV Community

Cover image for What is Docker Compose Watch and what problem does it solve?
Ajeet Singh Raina
Ajeet Singh Raina

Posted on • Updated on • Originally published at collabnix.com

What is Docker Compose Watch and what problem does it solve?

Containerization has become an integral part of modern software development, offering numerous benefits such as portability, scalability, and reproducibility. Docker Compose, a popular tool in the Docker ecosystem, simplifies the management of multi-container applications. With the release of Docker Compose v2.17, a new feature called "Docker Compose Watch" has been introduced, aiming to streamline the development workflow and address concerns around slow builds and developer experience. In this blog post, we will explore Docker Compose Watch, understand its functionalities, and see how it solves common challenges in containerized development.

Understanding Docker Compose Watch

Docker Compose Watch is an experimental file watch command that automates the update process for running Docker Compose services as developers edit and save their code. By monitoring specified file or directory paths on the host machine, Docker Compose Watch detects changes and performs corresponding actions within the service container. This capability enables developers to instantly see the impact of their code changes without manually triggering image builds or container restarts.

Docker Compose Watch is a feature of Docker Compose that allows you to automatically update your running Compose services as you edit and save your code. This is useful for development workflows where you want to see the changes you make to your code reflected in your running application immediately.

How does Compose Watch work?

Docker Compose Watch works by monitoring the files in your project directory for changes. When a file is changed, Compose will rebuild the corresponding service container and restart it. This ensures that your running application always has the latest code.

Adding Watch in Docker Compose

  • Add watch sections to one or more services in compose.yaml.
  • Launch a Compose project with docker compose up --build --wait.
  • Run docker compose alpha watch to start the file watch mode.
  • Edit service source files using your preferred IDE or editor.

Image11

The "watch" section contains two actions:

  • sync
  • rebuild

The "sync" action specifies a path to watch for changes in the host file system, and a corresponding target path inside the container to synchronize changes to.

The "rebuild" action specifies a path to watch for changes in the host file system, and triggers a rebuild of the container when changes are detected.

What problems does Compose Watch solve? What are its benefits?

The problem that Docker Compose Watch solves is the need to manually restart your services every time you make a change to your code. This can be time-consuming and disruptive, especially if you are making a lot of changes. With Docker Compose Watch, you can make changes to your code and see the results immediately, without having to restart your services.

Benefits and Use Cases

Docker Compose Watch offers several benefits that enhance the developer experience and simplify containerized development:

  • Rapid Feedback Loop: With Docker Compose Watch, developers receive immediate feedback on code changes. As they save their files, the running Compose services automatically update, eliminating the need for manual rebuilds and restarts. This accelerated feedback loop improves productivity and facilitates iterative development.

  • Reduced Build Time: By synchronizing only the changed files, Docker Compose Watch optimizes the build process, reducing the time required for image builds. It eliminates the need to rebuild the entire image for every code modification, making the development workflow more efficient.

  • Seamless Container Updates: Docker Compose Watch ensures that developers always work with the latest code inside the containers. As changes are detected, the relevant files are synced, and containers are recreated when necessary. This seamless update process prevents inconsistencies between development environments and production deployments.

Drawbacks of Compose Watch

Here are some of the drawbacks of using Docker Compose Watch:

  • It can increase the amount of CPU and memory usage.
  • If you make a lot of changes to your code, Compose may need to rebuild your service containers frequently. This can slow down your development workflow.

Overall, Docker Compose Watch is a powerful feature that can help you improve your development workflow. However, it is important to be aware of the potential drawbacks before using it. If you are using Docker Compose Watch and you notice that your development workflow is slowing down, you may need to reduce the amount of changes you make to your code or increase the amount of time between rebuilds.

Configuring Docker Compose Watch

To leverage Docker Compose Watch, a new section called "x-develop" needs to be added to the Compose YAML file. Within this section, the "watch" option is available, allowing developers to define the files or directories to monitor and the actions to be taken inside the container.

Let's take a look at an example:

services:
  web:
    build: .
    x-develop:
      watch:
        - action: sync
          path: ./web
          target: /src/web
        - action: rebuild
          path: package.json
Enter fullscreen mode Exit fullscreen mode

The x-develop section in your Docker Compose file allows you to configure watch options for your services. In this case, you are configuring two watch options:

  • The first watch option will watch the api/requirements.txt file and rebuild the service container if the file is changed.

  • The second watch option will watch the api/ directory and sync the changes to the /app/api/ directory in the container.

  • The action property of the watch option specifies what to do when the file is changed.

In the first case, the rebuild action will rebuild the service container. In the second case, the sync action will sync the changes to the /app/api/ directory in the container.

The target property of the watch option specifies the directory in the container where the changes should be synced. In this case, the target property is set to /app/api/, so the changes to the api/ directory will be synced to the /app/api/ directory in the container.

In the above example, the "web" service is configured to sync changes made in the ./web directory with the corresponding location /src/web inside the container using the "sync" action. This synchronization is especially useful when combined with frameworks supporting hot module reload. Additionally, changes to the package.json file trigger a rebuild of the image and recreation of the service container using the "rebuild" action.

Sample Application: Avatars

To demonstrate the capabilities of Docker Compose Watch, let's consider a sample application called "Avatars." The source code for this application is available at https://github.com/dockersamples/avatars.git. Follow these steps to run the application and experience Docker Compose Watch in action:

Clone the repository:

git clone https://github.com/dockersamples/avatars.git
cd avatars
Enter fullscreen mode Exit fullscreen mode

Examining the Compose file

services:
  api:
    image: avatars-api
    build:
      context: .
      dockerfile: ./deploy/api.dockerfile
    ports:
      - 5734:80
    x-develop:
      watch:
        - path: api/requirements.txt
          action: rebuild
        - path: api/
          target: /app/api/
          action: sync

  web:
    image: avatars-web
    build:
      context: .
      dockerfile: ./deploy/web.dockerfile
    ports:
      - 5735:5173
    x-develop:
      watch:
        - path: web/package.json
          action: rebuild
        - path: web/yarn.lock
          action: rebuild
        - path: web/
          target: /app
          action: sync
Enter fullscreen mode Exit fullscreen mode

The services section in your Docker Compose file defines the services that will be created. In this case, you are defining two services: api and web.

The api service will be built from the api.dockerfile file in the deploy directory. The api service will listen on port 5734. The x-develop section for the api service defines two watch options:

  • The first watch option will watch the api/requirements.txt file and rebuild the service container if the file is changed.
  • The second watch option will watch the api/ directory and sync the changes to the /app/api/ directory in the container.
  • The web service will be built from the web.dockerfile file in the deploy directory. The web service will listen on port 5735. The x-develop section for the web service defines three watch options:

  • The first watch option will watch the web/package.json file and rebuild the service container if the file is changed.

  • The second watch option will watch the web/yarn.lock file and rebuild the service container if the file is changed.

  • The third watch option will watch the web/ directory and sync the changes to the /app directory in the container.

Start the application:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Accessing the Application

Open your browser and access the app via https://localhost:5735

Image54

Enable Docker Compose Watch

docker compose alpha watch
Enter fullscreen mode Exit fullscreen mode

As you make changes to the Avatars application code, Docker Compose Watch will automatically sync the modified files and reflect the changes in the running containers, allowing you to observe the immediate impact of your code modifications.

Compose Watch Rebuild

Go to requirements.txt file under api/ directory and add a new package such as Django, for example.

docker compose alpha watch
watch command is EXPERIMENTAL
watching [/Users/ajeetsraina/july/avatars/api/requirements.txt /Users/ajeetsraina/july/avatars/api]
watching [/Users/ajeetsraina/july/avatars/web/package.json /Users/ajeetsraina/july/avatars/web/yarn.lock /Users/ajeetsraina/july/avatars/web]
change detected on /Users/ajeetsraina/july/avatars/api/requirements.txt
change detected on /Users/ajeetsraina/july/avatars/api/requirements.txt
Rebuilding api after changes were detected:
  - /Users/ajeetsraina/july/avatars/api/requirements.txt
[+] Building 3.3s (22/22) FINISHED
 => [api internal] load build definition from api.dockerfile                                                                                               0.0s
 => => transferring dockerfile: 403B                                                                                                                       0.0s
 => [api internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 95B                                                                                                                           0.0s
 => [api internal] load metadata for docker.io/library/python:3.10-slim-bullseye                                                                           3.2s
 => [web internal] load .dockerignore                                                                                                                      0.0s
 => => transferring context: 95B                                                                                                                           0.0s
 => [web internal] load build definition from web.dockerfile                                                                                               0.0s
 => => transferring dockerfile: 372B                                                                                                                       0.0s
 => [web internal] load metadata for docker.io/library/node:18-bullseye-slim                                                                               3.0s
 => [web auth] library/node:pull token for registry-1.docker.io                                                                                            0.0s
 => [api auth] library/python:pull token for registry-1.docker.io                                                                                          0.0s
 => [web stage-0 1/5] FROM docker.io/library/node:18-bullseye-slim@sha256:1ba1ddfc61b385b6436fd0fa0d1d42d322a0cd03c1ff110fa39e828511152aef                 0.0s
 => => resolve docker.io/library/node:18-bullseye-slim@sha256:1ba1ddfc61b385b6436fd0fa0d1d42d322a0cd03c1ff110fa39e828511152aef                             0.0s
 => [web internal] load build context                                                                                                                      0.0s
 => => transferring context: 62.89kB                                                                                                                       0.0s
 => CACHED [web stage-0 2/5] WORKDIR /app                                                                                                                  0.0s
 => CACHED [web stage-0 3/5] COPY web/package.json web/yarn.lock ./                                                                                        0.0s
 => CACHED [web stage-0 4/5] RUN --mount=type=cache,target=/cache/yarn   yarn install                                                                      0.0s
 => CACHED [web stage-0 5/5] COPY web/ ./                                                                                                                  0.0s
 => [web] exporting to image                                                                                                                               0.0s
 => => exporting layers                                                                                                                                    0.0s
 => => exporting manifest sha256:ad79cc385428229f574b4bc89bc9de673cb2b54ac7eb86a22b04f6f2d3db0da3                                                          0.0s
 => => exporting config sha256:6db11cb4c7bb5f3fbe830f929f01e90bdd26ac0b912951f746eb5c532ef1fb2c                                                            0.0s
 => => exporting attestation manifest sha256:a1a0747c695f6dfbc4570f3b12a0f08c25249205f7b99c33f28051ea8fbacf6d                                              0.0s
 => => exporting manifest list sha256:9c1bb9ad0715a0ce8366ba0b42c9a9cfb78dd5999f7e86046d295b39be24957e                                                     0.0s
 => => naming to docker.io/library/avatars-web:latest                                                                                                      0.0s
 => => unpacking to docker.io/library/avatars-web:latest                                                                                                   0.0s
 => [api stage-0 1/5] FROM docker.io/library/python:3.10-slim-bullseye@sha256:a704ba2899da520dacf80a8b048de02e37476842539a95abc2883fed935a6746             0.0s
 => => resolve docker.io/library/python:3.10-slim-bullseye@sha256:a704ba2899da520dacf80a8b048de02e37476842539a95abc2883fed935a6746                         0.0s
 => [api internal] load build context                                                                                                                      0.0s
 => => transferring context: 9.46kB                                                                                                                        0.0s
 => CACHED [api stage-0 2/5] WORKDIR /app                                                                                                                  0.0s
 => CACHED [api stage-0 3/5] COPY api/requirements.txt ./                                                                                                  0.0s
 => CACHED [api stage-0 4/5] RUN --mount=type=cache,target=/root/.cache/pip   pip install -r requirements.txt                                              0.0s
 => CACHED [api stage-0 5/5] COPY api/ ./api/                                                                                                              0.0s
 => [api] exporting to image                                                                                                                               0.0s
 => => exporting layers                                                                                                                                    0.0s
 => => exporting manifest sha256:0d90e53316887a00bbc3f70976c1731899856546570fe11e9b494428b4a0a319                                                          0.0s
 => => exporting config sha256:02553b53e56bd7bd4a00edc456d3715774dbf0c29442c4f29a6c90020d4a92ea                                                            0.0s
 => => exporting attestation manifest sha256:7b5e5d07ee0beebdc982a1221e94b54a0d73dcfd8f0e3ac98c0414362c42ef04                                              0.0s
 => => exporting manifest list sha256:17bd94f6e661dcdb358e0f5c5a65f8c367258525d03762198738071676906504                                                     0.0s
 => => naming to docker.io/library/avatars-api:latest                                                                                                      0.0s
 => => unpacking to docker.io/library/avatars-api:latest                                                                                                   0.0s
[+] Running 2/2
 ✔ Container avatars-web-1  Started                                                                                                                        0.6s
 ✔ Container avatars-api-1  Started
Enter fullscreen mode Exit fullscreen mode

Compose Watch Sync

Try replacing the docker_tshirt.svg file with your favourite color, then you will see sync updates in the docker compose alpha watch window.

To watch a specific file

Here are some more examples of how you can use Compose watch:

services:
  web:
    build: .
    command: 'npm start'
    # Enable compose watch
    x-develop:
      watch:
        - ./src/index.js
Enter fullscreen mode Exit fullscreen mode

In this example, Compose will only watch the index.js file in the src directory.

To watch a directory and all of its subdirectories:

services:
  web:
    build: .
    command: 'npm start'
    # Enable compose watch
    x-develop:
      watch:
        - ./src/**/*
Enter fullscreen mode Exit fullscreen mode

In this example, Compose will watch all files in the src directory and all of its subdirectories.

To watch a file and ignore changes to other files

services:
  web:
    build: .
    command: 'npm start'
    # Enable compose watch
    x-develop:
      watch:
        - ./src/index.js
        # Ignore changes to other files
        - !./src/other.js
Enter fullscreen mode Exit fullscreen mode

In this example, Compose will only watch the index.js file in the src directory. Any changes to other files will be ignored.

Conclusion

Docker Compose Watch is a valuable addition to the Docker Compose ecosystem, empowering developers with an efficient and streamlined containerized development workflow. By automating the update process for running services, Docker Compose Watch reduces build times, provides rapid feedback on code changes, and ensures that developers work with the latest code inside the containers.

Although an experimental feature, Docker Compose Watch demonstrates the commitment of Docker Compose to improve the developer experience and addresses the challenges associated with local container development. As developers embrace containerization for their daily workflow, Docker Compose Watch proves to be an indispensable tool for enhancing productivity and maintaining development environments that are in sync with production deployments.

Top comments (0)