Developer's Guide to Crontab Generator: Best Practices and Examples
August 18, 2026 · The Devs Tools Team
Cron is the standard Unix job scheduler, and its expression syntax has survived largely unchanged since the 1970s because it's compact and expressive enough to describe almost any recurring schedule in five whitespace-separated fields: minute, hour, day-of-month, month, and day-of-week. Each field accepts an asterisk (meaning "every value"), a specific number, a comma-separated list, a range (1-5), or a step value (*/15 for every 15 units). What trips up most developers is the interaction between the day-of-month and day-of-week fields: when both are restricted to something other than *, most cron implementations treat them as an OR condition rather than an AND — so 0 0 15 * 1 runs at midnight on the 15th of the month or every Monday, not only when the 15th happens to fall on a Monday. Cron also has no concept of time zones by default; it runs in whatever time zone the host system (or the crontab daemon's configured CRON_TZ, on systems that support it) is set to, which is a frequent source of off-by-several-hours bugs when a server's system clock is UTC but the schedule was written assuming local time. Some platforms extend the standard five fields with a sixth field for second-level resolution or shorthand strings like @daily, @hourly, and @reboot, but these are non-standard extensions — portable crontabs should stick to the five-field POSIX form.
[!TIP] Need to build a cron expression right now? Try our free, local Crontab Generator to visually construct and read schedule strings completely offline.
The Five Fields
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
* * * * *
Common Patterns
# Every 5 minutes
*/5 * * * *
# Every day at 2:30 AM
30 2 * * *
# Every weekday at 9:00 AM (Monday-Friday)
0 9 * * 1-5
# First day of every month at midnight
0 0 1 * *
# Every 6 hours
0 */6 * * *
# Twice a day, at 6 AM and 6 PM
0 6,18 * * *
Pitfalls Worth Knowing
- The OR trap: as noted above, restricting both day-of-month and day-of-week rarely does what you'd guess. If you actually want "the 15th, but only if it's a Monday," cron alone can't express that — you need application-level logic.
- Time zone assumptions: always verify what time zone the scheduling daemon actually runs in, especially in containerized environments where the base image may default to UTC regardless of your local expectations.
- Overlapping runs: cron doesn't know or care whether the previous invocation of a job finished. A job scheduled every minute that occasionally takes 90 seconds will pile up overlapping processes unless you add your own locking (e.g.
flock) around the command. - Missed schedules on downtime: standard cron does not "catch up" missed runs if the machine was off —
@rebootand monitoring/alerting are the usual mitigations for critical jobs.
Conclusion
Cron syntax is small enough to memorize but easy to get subtly wrong, especially around the day-of-month/day-of-week OR behavior and time zone assumptions. Building the expression visually field-by-field, and mentally reading it back before deploying, avoids the classic failure mode of a job that runs at 3 AM UTC instead of 3 AM local time — or twice as often as intended.
