Dreißig Sekunden. So lange habe ich gewartet, bis mein Docker-Container nach einer einzigen Code-Zeile neu gebaut war. Dann nochmal dreißig Sekunden. Und nochmal. Am Ende des Tages hatte ich mehr Zeit damit verbracht, Docker beim Bauen zuzusehen, als tatsächlich Code zu schreiben.
Oder: Wie ich lernte, die Rebuild-Hölle zu überleben und File-Synchronisation zu lieben
Falls du jemals beim fünfzehnten docker compose build in dieser Stunde gemurrt
hast “das muss doch besser gehen”, dann wirst du lieben, was Docker 2025
ausgeliefert hat. Der watch-Befehl ist jetzt GA (Generally Available) und wird
transformieren, wie du mit Containern entwickelst.
Das Problem: Rebuild-Hölle
Lass uns mal ehrlich sein, wie traditionelle Docker-Entwicklung aussieht:
# Eine Datei bearbeiten
vim src/Controller/UserController.php
# Container neu bauen
docker compose build
# ⏳ Building... (30-60 Sekunden)
# Neustarten
docker compose up
# ⏳ Starting... (10 Sekunden)
# Änderung testen
curl localhost:8000/users
# 🤦 Verdammt, ein Tippfehler
# Repeat ad nauseam
Kennste das? Du bist im Flow, machst schnelle Iterationen, und Docker reißt dich ständig raus mit diesen schmerzhaften Rebuild-Zyklen. Klar, du könntest Volumes mounten und hoffen, dass deine Anwendung Hot Reload kann. Aber das ist fragmentiert, inkonsistent zwischen Frameworks und bricht oft auf subtile Weise mit File-Permissions oder verschachtelten Dependencies.
Der eigentliche Knaller? Du baust komplette Container neu, nur um ein paar geänderte Dateien zu kopieren.
Enter Docker Compose Watch
Docker Compose Watch eliminiert den Rebuild-Zyklus für die Entwicklung. Es überwacht deine Source-Dateien und synchronisiert Änderungen in Echtzeit in laufende Container – keine Rebuilds, keine Restarts (außer du willst sie).
Stand 2025 ist es production-ready, battle-tested und lächerlich einfach einzurichten.
Der Quick Win
Hier ist das minimale Setup, das deine Sanität rettet:
services:
web:
build: .
ports:
- "8000:8000"
develop:
watch:
- action: sync
path: ./src
target: /app/src
Starten mit:
docker compose watch
Das war’s. Ändere eine Datei in ./src, und Docker synchronisiert sie sofort
nach /app/src in deinem Container. Kein Rebuild. Kein Restart. Nur pures,
sofortiges Feedback.
Zwei Varianten von Watch
Docker gibt dir zwei Befehle, je nachdem was du sehen willst:
# Zeigt nur Watch-Aktivität (File-Syncs, Rebuilds)
docker compose watch
# Zeigt alles (Watch + alle Container-Logs)
docker compose up --watch
Ich nutze watch, wenn ich an Frontend-Arbeit fokussiert bin und keine
Server-Logs brauche. Ich nutze up --watch, wenn ich Full-Stack-Probleme
debugge und sowohl File-Änderungen als auch Application-Output sehen muss.
Die drei Watch-Actions
Docker Compose Watch unterstützt drei Synchronisations-Strategien, jede optimiert für unterschiedliche Szenarien.
Action 1: sync (Der schnelle Weg)
develop:
watch:
- action: sync
path: ./src
target: /app/src
Was es macht: Kopiert geänderte Dateien direkt in den laufenden Container.
Wann nutzen: Application-Code, den dein Framework automatisch hot-reloaded (PHP-Scripts, Python-Module, JavaScript-Dateien).
Geschwindigkeit: Instant. Typischerweise 1-2 Sekunden selbst für große Dateien.
Gotcha: Deine Anwendung muss Dateiänderungen erkennen. Das funktioniert super mit:
- PHP-FPM (verarbeitet Dateien bei jedem Request)
- Node.js mit nodemon
- Python mit watchdog
- Jedem Framework mit eingebautem Hot Reload
Action 2: rebuild (Die nukleare Option)
develop:
watch:
- action: rebuild
path: package.json
Was es macht: Triggert einen kompletten Container-Rebuild, wenn die Datei sich ändert.
Wann nutzen: Dependency-Dateien oder Konfiguration, die einen Rebuild erfordert (package.json, composer.json, Dockerfile, requirements.txt).
Geschwindigkeit: Gleich wie manueller Rebuild (30-60 Sekunden), aber automatisch.
Warum nützlich: Du bekommst instant Sync für Code-Änderungen und automatische Rebuilds nur wenn nötig. Best of both worlds.
Action 3: sync+restart (Der Mittelweg)
develop:
watch:
- action: sync+restart
path: ./config
target: /app/config
Was es macht: Synchronisiert die Datei und startet den Main-Process des Containers neu.
Wann nutzen: Konfigurationsdateien, die deine Anwendung nur beim Start liest (Environment-Configs, Service-Definitionen, nginx.conf).
Geschwindigkeit: Schneller Sync + schneller Restart (5-10 Sekunden).
Wichtig: Das startet den Prozess neu, nicht den kompletten Container. Viel schneller als ein Rebuild.
Real-World-Setup: Symfony-Anwendung
Lass uns mal eine komplette Development-Umgebung für eine Symfony-PHP-Anwendung bauen. Hier glänzt Docker Compose Watch richtig.
services:
php:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./:/app
depends_on:
- database
develop:
watch:
# Sync PHP-Source-Code sofort
- action: sync
path: ./src
target: /app/src
# Sync Templates
- action: sync
path: ./templates
target: /app/templates
# Sync Public-Assets
- action: sync
path: ./public
target: /app/public
# Rebuild wenn Dependencies sich ändern
- action: rebuild
path: composer.json
- action: rebuild
path: composer.lock
# Restart wenn Config sich ändert
- action: sync+restart
path: ./config
target: /app/config
database:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: user
POSTGRES_PASSWORD: secret
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Was das dir gibt:
- Controller bearbeiten → instant Sync → Browser refreshen → Änderungen sehen
- Template bearbeiten → instant Sync → refresh → Änderungen sehen
- composer.json bearbeiten → automatischer Rebuild → Container bereit mit neuen Dependencies
- config/services.yaml bearbeiten → Sync + Restart → Container lädt Konfiguration neu
Der Workflow:
# Alles mit Watch starten
docker compose up --watch
# In einem anderen Terminal, normal arbeiten
vim src/Controller/UserController.php
# Watch-Logs zeigen: Syncing src/Controller/UserController.php
# Browser öffnen, Änderungen sofort sehen
# Keine manuelle Intervention nötig
Multi-Service Watch: Der Full Stack
Hier wird’s interessant. Du kannst mehrere Services gleichzeitig watchen, jeder mit eigenen Sync-Regeln.
services:
# Backend API (PHP/Symfony)
api:
build: ./api
develop:
watch:
- action: sync
path: ./api/src
target: /app/src
- action: rebuild
path: ./api/composer.json
# Frontend (React/Vite)
frontend:
build: ./frontend
develop:
watch:
- action: sync
path: ./frontend/src
target: /app/src
- action: sync
path: ./frontend/public
target: /app/public
- action: rebuild
path: ./frontend/package.json
# Worker (Background Jobs)
worker:
build: ./worker
develop:
watch:
- action: sync+restart
path: ./worker/src
target: /app/src
Alles laufen lassen:
docker compose up --watch
Jetzt hast du:
- Frontend mit Vite Hot Reload
- Backend mit PHP File Watching
- Worker, der bei Code-Änderungen neustartet
Alles automatisch synchronisiert. Das ist die Developer-Experience, die wir die ganze Zeit verdient hätten.
Initial Sync: Das September-2025-Feature
Docker hat im September 2025 ein sneaky nützliches Feature hinzugefügt:
initial_sync.
develop:
watch:
- action: sync
path: ./src
target: /app/src
initial_sync: true
Was es macht: Synchronisiert alle Dateien sofort, wenn du
docker compose watch startest, bevor es auf Änderungen wartet.
Warum es wichtig ist: Wenn du einen Container startest und dann watch
startest, könnte dein Container veraltete Dateien haben. Mit
initial_sync: true stellt Docker sicher, dass von Anfang an alles
synchronisiert ist.
Wann nutzen: Immer. Es gibt keinen Nachteil, und es verhindert komische “warum läuft mein Container mit altem Code?”-Bugs.
Profiles: Umgebungsbasierte Services
Während wir dein Docker-Setup modernisieren, lass uns mal über Compose Profiles reden. Die sind perfekt für konditionale Services basierend auf deiner Umgebung.
services:
# Läuft immer
app:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
# Nur in Development
mailhog:
image: mailhog/mailhog
profiles: ["dev"]
ports:
- "8025:8025"
# Nur in Development
adminer:
image: adminer
profiles: ["dev"]
ports:
- "8080:8080"
# Nur für Production-ähnliches Testing
monitoring:
image: prom/prometheus
profiles: ["prod"]
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
Development-Workflow:
docker compose --profile dev up --watch
Du bekommst die App, Mailhog für E-Mail-Testing und Adminer für Datenbank-Inspektion.
Production-Simulation:
docker compose --profile prod up
Du bekommst die App und Monitoring, ohne Development-Tools.
Nur die App:
docker compose up
Clean und simple.
Die Gotchas (Was ich auf die harte Tour gelernt habe)
File-Permissions
Docker’s watch synchronisiert Dateien mit den User-Permissions des Containers.
Wenn dein Container als www-data läuft, aber deine Host-Dateien deinem User
gehören, könntest du Permission-Errors sehen.
Lösung: User-IDs in deinem Dockerfile matchen:
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN groupmod -g ${GROUP_ID} www-data && \
usermod -u ${USER_ID} -g ${GROUP_ID} www-data
Build mit deinen IDs:
docker compose build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)
Ignore-Patterns
Watch hat noch keine eingebauten Ignore-Patterns. Wenn du ein Verzeichnis mit
node_modules oder vendor synchronisierst, synchronisierst du alles.
Workaround: Sei spezifisch mit Pfaden:
develop:
watch:
# ❌ Synchronisiert alles inklusive node_modules
- action: sync
path: ./
target: /app
# ✅ Synchronisiere nur was du brauchst
- action: sync
path: ./src
target: /app/src
- action: sync
path: ./public
target: /app/public
Volumes vs Watch
Wenn du bereits Volumes gemountet hast, könnte watch redundant erscheinen. Der Unterschied:
Volume Mount: Bidirektional, persistent, teilt sich die gleiche Inode Watch Sync: Einseitig (Host → Container), isoliert, sicherer für node_modules-Konflikte
Du kannst beides nutzen:
services:
app:
volumes:
# Volume für persistente Daten
- db_data:/var/lib/mysql
develop:
watch:
# Watch für Code-Änderungen
- action: sync
path: ./src
target: /app/src
Multiple Services seit Februar 2025 gefixt
Frühe Versionen von watch hatten Probleme mit mehreren Services. Wenn du Docker Compose 2.25 oder neuer nutzt (Februar 2025 Release), ist das gefixt. Multiple Services mit watch funktionieren tadellos.
Wenn du eine ältere Version hast:
docker compose version
Upgrade, wenn du unter 2.25 bist.
Das Node.js Hot-Reload-Setup
Hier ist ein komplettes Node.js/Express-Beispiel mit echtem Hot Reload:
Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
# Nodemon global installieren für Hot Reload
RUN npm install -g nodemon
CMD ["nodemon", "server.js"]
compose.yaml:
services:
api:
build: .
ports:
- "3000:3000"
environment:
NODE_ENV: development
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: sync
path: ./public
target: /app/public
- action: rebuild
path: package.json
Die Magie: Nodemon erkennt Dateiänderungen im Container und startet den Node-Prozess neu. Watch synchronisiert Dateien vom Host zum Container. Zusammen kreieren sie nahtlosen Hot Reload.
Starten:
docker compose up --watch
Bearbeite irgendeine Datei in ./src, und nodemon startet automatisch neu. Null
manuelle Intervention.
Bonus-2025-Features, die du kennen solltest
Während du deinen Docker-Workflow modernisierst, hier sind andere Perlen aus 2025:
CTRL+Z Background-Mode
docker compose up --watch
# Drücke CTRL+Z
# Compose geht in den Hintergrund, kehrt zum Terminal zurück
Keine weiteren Terminal-Fenster mehr öffnen. Das ist chef’s kiss.
Compose Bridge
Konvertiere dein Docker Compose zu Kubernetes:
docker compose bridge convert --format kubernetes
Oder generiere Helm Charts:
docker compose bridge convert --format helm
Nützlich für Staging/Production-Deployments, während du deine lokale Entwicklung in Compose behältst.
Bake als Default-Builder
Für komplexe Builds mit mehreren Plattformen:
services:
app:
build:
context: .
platforms:
- linux/amd64
- linux/arm64
Docker nutzt jetzt BuildKit Bake unter der Haube, was Multi-Platform-Builds signifikant schneller macht.
Die Transformation
Lass uns mal drüber reden, was das wirklich für deinen Tag bedeutet.
Vor Docker Compose Watch:
- Datei bearbeiten
- 30-60 Sekunden auf Rebuild warten
- 10 Sekunden auf Restart warten
- Änderung testen
- 50-100 Mal pro Tag wiederholen
- Verschwendete Zeit: Stunden
Nach Docker Compose Watch:
- Datei bearbeiten
- 1-2 Sekunden auf Sync warten
- Änderung testen
- Unendlich wiederholen
- Verschwendete Zeit: Minuten
Die Zahlen sind wichtig, aber das Gefühl ist wichtiger. Du bleibst im Flow. Du machst keinen Context-Switch zu Twitter während du auf Builds wartest. Du verlierst deinen Gedankenfaden nicht.
Wann Watch NICHT nutzen
Lass uns ehrlich über die Limitierungen sein:
Production: Niemals. Watch ist ein Development-Tool. Deine Production-Container sollten immutable sein, einmal gebaut, überall deployed.
CI/CD: Nope. Deine CI-Pipeline sollte jedes Mal saubere Images from scratch bauen.
Compilierte Sprachen mit komplexen Builds: Wenn deine Go/Rust/Java-Anwendung 5 Minuten zum Kompilieren braucht, wird watch nicht bei der Kompilierung selbst helfen. Du brauchst immer noch den Build-Step. Aber watch kann Source-Dateien syncen und Rebuilds automatisch triggern.
Shared Volumes funktionieren gut: Wenn du mit Volume-Mounts zufrieden bist und sie für dein Setup funktionieren, ändere nichts. Watch glänzt, wenn Volumes Probleme kreieren (node_modules-Konflikte, Performance auf Mac/Windows, Permission-Issues).
Die Alternativen (Und warum Watch gewinnt)
Volume Mounts
Pros:
- Simple, gibt’s schon ewig
- Keine spezielle Konfiguration
Cons:
- Bidirektional (Container kann Host-Dateien modifizieren)
- Performance-Probleme auf Mac/Windows
- node_modules-Konflikte machen dich wahnsinnig
- Permission-Probleme
Verdict: Super für simple Cases, schmerzhaft im Scale
docker-sync
Pros:
- Löst Mac/Windows-Performance
- Reifes Ecosystem
Cons:
- Third-Party-Tool
- Extra Daemon zum Laufen bringen
- Komplexe Konfiguration
Verdict: War notwendig, jetzt obsolet mit watch
Manuelle Rebuild-Scripts
Pros:
- Totale Kontrolle
Cons:
- Du maintainst Custom-Tooling
- Fehleranfällig
- Jeder im Team muss dein Setup kennen
Verdict: Hör auf, das Rad neu zu erfinden
Docker Compose Watch
Pros:
- Native Docker-Feature
- Null Dependencies
- Deklarative Konfiguration
- Funktioniert plattformübergreifend
- Maintained von Docker, Inc.
Cons:
- Relativ neu (aber GA in 2025)
- Keine Ignore-Patterns yet
Verdict: Der moderne Standard
Heute loslegen
Hier ist dein Action-Plan:
1. Docker upgraden:
docker compose version
# Sollte 2.25.0 oder höher sein
2. Watch zu deiner compose.yaml hinzufügen:
develop:
watch:
- action: sync
path: ./src
target: /app/src
3. Watching starten:
docker compose watch
4. Eine Datei bearbeiten und lächeln:
Beobachte, wie der Sync in 1-2 Sekunden passiert. Spüre die Zeit, die du sparst. Frag dich, warum du das nicht schon früher gemacht hast.
Fazit
Docker Compose Watch ist eines dieser Features, die auf dem Papier klein wirken, aber fundamental deine tägliche Experience verändern. Das Ende der Container-Rebuild-Hölle ist keine ferne Utopie – es ist hier, es ist stabil, und es ist lächerlich einfach zu adoptieren.
Drei Änderungen, die deinen Docker-Development transformieren:
- Füge
develop.watch-Blöcke zu deinen Services hinzu - Nutze
docker compose up --watchstattup - Hör auf, auf Rebuilds zu warten
Probier’s bei deinem nächsten Projekt aus. Besser noch, füge es einem existierenden Projekt hinzu und spüre den Unterschied sofort. Du wirst dich fragen, wie du jemals den alten Weg toleriert hast.
Jetzt entschuldige mich, ich hab Code zu schreiben. Und zum ersten Mal seit Jahren werde ich nicht die Hälfte meines Tages damit verbringen, Docker beim Bauen von Images zuzusehen.
Ressourcen:
Hast du eine clevere Watch-Konfiguration oder ein Gotcha, das ich verpasst habe? Drop es in die Comments. Lass uns zusammen bessere Development-Workflows bauen.