Developer Toolbox

Cron: every month

Midnight on the first day of each month, twelve runs a year. @monthly is a shorthand for the same expression.

Open in Cron Parser The expression is filled in: change it and watch the next runs.

Expression

0 0 1 * *
Meaning

At 00:00 on day 1 of every month

Next 5 runs

Your time zone

The same schedule on other platforms

PlatformWritten asNote
Linux crontab0 0 1 * *Five fields, in the server's local time zone. A % in the command has to be escaped as \%.
GitHub Actions- cron: '0 0 1 * *'Five fields, in UTC unless a timezone (an IANA name such as Europe/Warsaw) is set next to cron. Default branch only. The shortest interval is 5 minutes; when GitHub is busy, runs start late and some are dropped.
Kubernetes CronJobschedule: "0 0 1 * *"Five fields, in the controller's time zone unless spec.timeZone is set (Kubernetes 1.27 and later). concurrencyPolicy decides what happens when runs overlap.
systemd timerOnCalendar=monthlyIts own calendar syntax, in a .timer unit, local time. hourly, daily and monthly match cron, but weekly means Monday. Persistent=true catches up on runs missed while the machine was off.
AWS EventBridgecron(0 0 1 * ? *)Six fields, the last one the year; one day field must be ?, and day of week 1 is Sunday. Rules run in UTC; EventBridge Scheduler accepts a time zone.
Quartz / Spring0 0 0 1 * ?Six fields, seconds first. Quartz needs ? in one of the day fields and counts Sunday as 1; Spring accepts ? and numbers days like cron.

Common mistakes

  • Day 31 skips months

    0 0 31 * * runs only in the seven months that have a 31st. Cron doesn't move the run to the last day of a shorter month.

  • The last day of the month

    Standard cron can't say it. Quartz and EventBridge have L (cron(0 0 L * ? *)). In crontab, run on days 28-31 and let the job check that tomorrow is the 1st: 0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && job.sh. Note the \%: an unescaped % ends the command in a crontab line.

  • Monthly reports

    A report for the month that just ended belongs on the 1st, as here, but a few minutes after midnight gives late data time to arrive: 30 0 1 * *.