Skip to content
Webmaster Tools

Cron once a month

To run a cron job once a month use @monthly, which is 0 0 1 * *, or pick your own day. Why days 29-31 skip months, and why rate(30 days) is not monthly.

Cron expression
0 0 1 * *
See the next run times

The expression

0 0 1 * *

Runs once a month, at 00:00 on the 1st. The @monthly macro means exactly this, so these crontab lines are the same:

@monthly   /usr/local/bin/monthly-report.sh
0 0 1 * *  /usr/local/bin/monthly-report.sh
Field Value Meaning
Minute 0 at minute 0
Hour 0 at midnight
Day of month 1 the 1st
Month * every month
Day of week * any day of the week

Picking the day

A monthly job only needs a single day of the month plus a fixed minute and hour. The 1st is the convention, not a rule:

Schedule Expression
1st at midnight (@monthly) 0 0 1 * *
The 5th at 9am 0 9 5 * *
The 28th at 3am (exists in every month) 0 3 28 * *
Last day of the month 0 0 28-31 * * plus a test
Twice a month 0 0 1,15 * *
Every three months 0 0 1 1,4,7,10 *

Days 1 to 28 occur in every month. Pick a day above 28 and cron simply skips the months that don't have it: 0 0 31 * * runs only seven times a year, and 0 0 30 * * never runs in February. Cron doesn't move the run to the nearest valid day.

Where to write it

  • crontab (Linux, macOS): @monthly command or 0 0 1 * * command in crontab -e, in the server's time zone. Many distributions also have /etc/cron.monthly/, run by anacron, which catches up when the machine was off on the 1st.
  • GitHub Actions: cron: '0 0 1 * *' in UTC; macros aren't accepted. A monthly job in a quiet public repository can stop silently: GitHub disables scheduled workflows after 60 days without repository activity, which is only two runs.
  • Kubernetes CronJob: schedule: "@monthly" or "0 0 1 * *", with timeZone:. Set startingDeadlineSeconds so a run missed during an outage is still started later.
  • AWS EventBridge: cron(0 0 1 * ? *). There is rate(30 days) too, but that is every 30 days from the rule's creation, drifting a day or two against the calendar every month. For "monthly", use the cron form.

Common mistakes

  • * * 1 * * runs every minute on the 1st: 1,440 runs.
  • 0 0 * 1 * is every day in January, not once a month. The month field restricts months; the day-of-month field picks the day.
  • A day that doesn't exist. 0 0 31 * * skips April, June, September, November and February.
  • Nobody notices it failed. A job that runs twelve times a year has twelve chances to be seen. Alert on failure, or on a missing run, rather than relying on someone checking.

See the next twelve runs in the Cron Expression Parser.