Linux Cron & Task Scheduling
Cron syntax, user vs system crontabs, /etc/cron.d vs /etc/crontab, environment pitfalls, systemd timers as the modern alternative, and debugging strategies. Essential for any infrastructure or backend role.
Overview
What cron is
Cron is the Unix daemon for scheduled command execution. The modern cron daemon on most Linux distributions is vixie-cron or cronie, and the syntax has been stable for decades.
Where cron matters in DevOps
- Periodic server maintenance — Backups, log rotation, report generation
- Scheduled CI pipelines — GitHub Actions schedule:, Jenkins "Build periodically" and Kubernetes CronJobs all use the same five-field syntax
- "Why didn't my job run" incidents — Almost always environment differences or time zone confusion
Three gotchas behind 80% of cron incidents
- Environment — PATH is typically /usr/bin:/bin, HOME is the user's home, SHELL defaults to /bin/sh. Scripts relying on a rich PATH, NVM, conda or bash syntax silently fail — Absolute paths for every executable, or PATH= at the top of the crontab
- Output — Cron mails stdout+stderr to the crontab owner via the local MTA; most servers have no MTA, so output is discarded — Add >> /var/log/myjob.log 2>&1 to every command
- The user — User crontabs (crontab -e, no user column) vs system crontabs (/etc/crontab and /etc/cron.d/*, with an extra user column) — Mixing them causes permission errors that look like the job isn't running
For new systems: systemd timers
> [!TIP] Prefer systemd timers for new infrastructure: full journal logging, Persistent=true for missed fires, resource limits, and integration with the dependency graph. Cron is still ubiquitous and worth understanding deeply.
Key concepts
- crontab command
- Manage the per-user crontab (stored in /var/spool/cron/crontabs/): User crontab format (no USER column):
- /etc/cron.d and system crontabs
- System crontabs run commands as a specified user (the extra column): Drop-in files in /etc/cron.d/ must have no extensions and no world-write permission — cron ignores files with wrong permissions silently. Unlike user crontabs, these are managed by package managers or Ansible/Puppet and survive user removal. The /etc/cron.{hourly,daily,weekly,monthly}/ directories are simpler: drop an executable script there and run-parts executes it at the appropriate interval. No schedule expression needed — just the executable bit and correct directory.
- Common cron expression patterns
- Use crontab.guru to verify expressions interactively. Always think in UTC — cron reads the system timezone unless CRON_TZ is set.
- systemd timer units
- Two files per scheduled task. The timer activates the matching service. OnCalendar mirrors cron but is more readable: weekly, monthly, Sat *-*-* 04:00:00. OnBootSec=2min fires 2 minutes after boot — better than @reboot with no delay control.
- Debugging cron failures
- Standard debugging workflow: Common root causes of "cron job doesn't run": — Wrong file permissions on /etc/cron.d/ (world-writable = ignored silently) — Missing executable bit on the script — PATH doesn't include the binary — Script uses bash-isms but SHELL=/bin/sh (fix: add #!/bin/bash shebang, set SHELL=/bin/bash in crontab) — NVM/rbenv/conda active in interactive shell but not in cron (fix: use absolute paths) — Windows line endings (\r\n) in the crontab file — silently breaks parsing (fix: dos2unix)
When to use it
- Any role involving Linux server administration, infrastructure engineering, or SRE
- Designing or debugging scheduled jobs: backups, report generation, log rotation, health checks
- Kubernetes: CronJob resources use the identical five-field cron syntax
- GitHub Actions: the schedule: trigger uses vixie-cron syntax (UTC timezone always)
- Jenkins: job scheduler ("Build periodically") and SCM polling use the same five-field format
Interview questions
- Write a cron expression for: run a backup every weekday at 2:30 AM, and a report every Sunday at 8 AM. What file would you put this in and why?
- A script runs perfectly when executed manually but fails silently in cron. Walk through your diagnosis.
- You need to ensure a cleanup job on a fleet of 50 servers doesn't hammer a shared database all at once. How do you implement the schedule?
- Compare cron and systemd timers — when would you choose one over the other?
- How do Kubernetes CronJobs differ from Linux cron, and what are the key pitfalls?
Sign up free to read the full topic
More DevOps topics
- Kubescape and Kubernetes Runtime Security
- Kustomization and Reconciliation
- Lease and Reservation Control Planes
- libstdc++, libc++, glibc and Symbol Versioning
- Lifecycle Hooks and Tests
- Linking Deep Dive
- Local Kubernetes Cluster Setup (minikube / kind / k3d)
- Log Aggregation
- Microservices Design
- Migration and Production Patterns
- Monitoring and Troubleshooting
- Monorepo Build Systems
Start free on Cariara · Coding problems · System design studio