Skip to content

[BUG] develop.watch initial_sync: true does not fire at container start #13725

Description

@mecampbellsoup

Description

develop.watch entries with initial_sync: true do not copy files from host to container at container creation time. Change-triggered syncs work correctly — only initial_sync is affected.

Steps To Reproduce

docker-compose.yml:

services:
  test:
    image: python:3.14-slim
    command: sleep infinity
    develop:
      watch:
        - path: ./src
          action: sync
          target: /app/src
          initial_sync: true
mkdir -p src && echo "hello" > src/test.txt
docker compose up --watch -d
sleep 30
docker exec <container> ls /app/src/   # → "No such file or directory"

# But change-triggered sync works:
touch src/test.txt
sleep 10
docker exec <container> ls /app/src/   # → test.txt appears

Observed Behavior

  • Container starts and runs successfully
  • ⦿ Watch enabled message appears in compose output
  • /app/src/ does NOT exist inside the container after 30+ seconds
  • After touching src/test.txt on the host, compose watch detects the change and syncs — /app/src/test.txt appears

Expected Behavior

With initial_sync: true, files should be copied from host to container at compose startup, before the main process starts. Per the documentation: "If initial_sync is set to true, Compose copies the watched files to the container when the service is started."

Environment

  • Docker Desktop for Mac (Apple Silicon)
  • Docker Compose v2.35+ (tested with latest stable as of 2026-04-10)
  • macOS 15.4 (Darwin 25.4.0)
  • Reproducible across multiple compose projects and file types

Notes

  • sync entries for individual files (e.g., pytest.ini → /app/pytest.ini) DO work with initial_sync: true
  • sync entries for directories (e.g., docker/pythonocc → /app/docker/pythonocc) do NOT fire initial_sync
  • The distinction may be file vs. directory syncing behavior

Activity

  1. trinhchien commented on Apr 11, 2026

    @trinhchien

    I was able to reproduce this locally and traced it to initialSyncFiles() in pkg/compose/watch.go.

    initial_sync was filtering files using the image creation time, so existing host files could be skipped during startup sync if their mtime was older than the image. That matches the behavior described here: startup sync is empty, but change-triggered sync works after touching the file.

    I opened a fix here: #13728

    The patch removes the image-time filter for initial_sync and adds tests for both directory and single-file watch paths.

  2. tsamarasinghe commented on May 20, 2026

    @tsamarasinghe

    any news about this ?

  3. NathanSavageKaimai commented on Jul 28, 2026

    @NathanSavageKaimai

    Hey, I saw the PR was marked stale and closed. Is this still planned?

    For anyone finding this thread, one workaround is just to write a utility script that updates the timestamp on your source files.

    Heres mine

    /**
     * Must run AFTER `docker compose build` and BEFORE watch starts, e.g.:
     *   docker compose build
     *   node scripts/touch-src-for-watch.mjs
     *   docker compose watch
     */
    import { readdir, utimes } from 'node:fs/promises';
    import { join, sep } from 'node:path';
    
    const roots = ['apps', 'packages'];
    const skipDirs = new Set(['node_modules', 'dist', '.angular', 'coverage']);
    const syncSegments = new Set(['src', 'public']);
    const now = new Date();
    
    function isUnderSyncTree(path) {
      const parts = path.split(sep);
      return parts.some((part) => syncSegments.has(part));
    }
    
    async function walk(dir) {
      let entries;
      try {
        entries = await readdir(dir, { withFileTypes: true });
      } catch {
        return;
      }
    
      for (const entry of entries) {
        const path = join(dir, entry.name);
        if (entry.isDirectory()) {
          if (skipDirs.has(entry.name)) continue;
          await walk(path);
          continue;
        }
        if (isUnderSyncTree(path)) {
          await utimes(path, now, now);
        }
      }
    }
    
    for (const root of roots) {
      await walk(root);
    }
  4. rocket-micha commented on Jul 31, 2026

    @rocket-micha

    Any plans here? 👀 This is a very frustrating bug

  5. added a commit that references this issue on Aug 20, 2026
    a515d44
  6. added a commit that references this issue on Aug 20, 2026
    ea8d9bc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions