crontool
Paste a schedule, read it in English, see the next runs.

Running a Docker Compose Command with Cron

cd into the directory holding compose.yaml so Docker Compose finds it, then call the full docker path. For scheduled tasks, docker compose run --rm a service is cleaner than exec because it doesn't need the container already running.

The crontab line

0 2 * * * cd /opt/app && /usr/bin/docker compose run --rm worker python job.py >> /var/log/compose-cron.log 2>&1

The cd matters — Compose looks for compose.yaml/docker-compose.yml in the working directory.

run --rm vs exec

run --rm starts a fresh container for the task and removes it after — ideal for cron. exec runs inside an already-running container: docker compose exec -T worker python job.py (use -T since cron has no TTY).

Permissions

The cron user must be in the docker group, or run the job from root's crontab.

FAQ

How do I run docker compose from cron?

cd to the compose directory and use the full docker path: 0 2 * * * cd /opt/app && /usr/bin/docker compose run --rm worker python job.py.

Should I use run or exec in a cron compose job?

Use run --rm for one-off scheduled tasks — it doesn't need the container running. Use exec -T only to run inside an already-running container.

Why does docker compose fail with no TTY in cron?

Cron has no terminal. Add -T to docker compose exec to disable TTY allocation.