Docker Compose Tip #83: Why up recreated containers that never changed

A service recreates on every single docker compose up. No file change, no rebuild, nothing actually different about the image. Before Compose 5.5.0, that wasn’t a flaky environment, it was a real bug class in how Compose decided an image had changed. One image, three ways to name its digest Compose decides whether to recreate a container by comparing the image’s current identity against a label it recorded last time, com.docker.compose.image. Before 5.5.0, that identity was computed differently depending on how the image got there: ...

September 9, 2026 · 3 min · 578 words · Guillaume Lours

Docker Compose Tip #80: additional_contexts for multi-context builds

A Dockerfile has one build context, the directory you point docker build at. That’s enough for the vast majority of builds, but sometimes you need files from somewhere else: a base image, a separate git repository, a local directory outside the project root, or another service’s build output. additional_contexts lets you wire all of those into a single build. The basic shape Under build:, declare named contexts. Inside the Dockerfile, reference them with COPY --from=<name>: ...

June 24, 2026 · 4 min · 640 words · Guillaume Lours

Docker Compose Tip #67: Controlling image pulls with pull_policy

By default, Compose pulls an image when it’s missing locally and uses the cached one otherwise. pull_policy lets you change that behavior per service. The policies services: web: image: nginx pull_policy: always Available values: missing (default when no build: is defined): pull only if the image is not present locally. Alias: if_not_present. Note: the latest tag is always pulled even with this policy. always: pull on every up, even if the local image is recent never: don’t pull, fail if the image is missing build: build the image, rebuilds even if it’s already present locally daily: check the registry if the last pull was more than 24 hours ago weekly: check the registry if the last pull was more than 7 days ago every_<duration>: check the registry if the last pull was older than the given duration. Units: w, d, h, m, s (or any combination, e.g. every_12h, every_30m, every_1d12h) When to use each always for development against a fast-moving tag: ...

May 25, 2026 · 3 min · 475 words · Guillaume Lours

Docker Compose Tip #46: Build args vs environment variables

Build args and environment variables both pass values to your containers, but they work at different times and serve different purposes. Mixing them up is a common source of confusion. Build args: build-time only Build args are available during docker build and are not present in the running container: services: app: build: context: . args: NODE_VERSION: "20" APP_VERSION: "2.1.0" In the Dockerfile, they’re consumed with ARG: ...

March 30, 2026 · 3 min · 471 words · Guillaume Lours

Docker Compose Tip #45: Multi-stage builds with target

Multi-stage Dockerfiles let you define multiple build stages. With the target option in Compose, you can choose which stage to build — giving you different images from the same Dockerfile. A multi-stage Dockerfile # Stage 1: dependencies FROM node:20-slim AS deps WORKDIR /app COPY package*.json ./ RUN npm ci # Stage 2: development (with dev dependencies and tools) FROM deps AS dev RUN npm install --include=dev COPY . . CMD ["npm", "run", "dev"] # Stage 3: build FROM deps AS build COPY . . RUN npm run build # Stage 4: production (minimal) FROM node:20-slim AS production WORKDIR /app COPY --from=build /app/dist ./dist COPY --from=deps /app/node_modules ./node_modules CMD ["node", "dist/index.js"] Targeting stages in Compose Use target to pick which stage to build: ...

March 27, 2026 · 2 min · 354 words · Guillaume Lours