@monthly in production
What @monthly actually does
@monthly expands to 0 0 1 * * — 00:00 on day 1 of every month. Unlike "last day of the month" schedules (which need the L flag in Quartz/AWS, or day 28-31 trickery in Unix cron), day 1 is the same length in every month, so the schedule needs no special handling. systemd's OnCalendar=monthly matches it, and Celery beat writes crontab(day_of_month=1).
The 1st is where the month-start workload lives: billing and invoice runs, subscription renewals, month-end report generation, credential and password rotations that expire monthly, storage snapshots pruned on a monthly cadence. Essentially anything a business accounts for by the calendar month keys off this one timestamp.
The 1st-of-the-month stampede
Because everyone keys off the 1st, the 00:00 on the 1st slot is the most contended minute of the month: payment processors, DNS providers, and internal batch queues all see their monthly peak. If your job talks to a third-party API, moving to the 2nd or 3rd (0 0 2 * *) buys an empty road for the price of one day's lag. For internal batch systems the same shift decouples your run from every other team's.
One more planner's note: a job at 00:00 on the 1st is really "end of the previous month" in disguise. If it aggregates or reports on month M, all of M's data must be closed out before the job fires — fine for logs and metrics, risky for anything with late-arriving records (refunds, timezone-shifted orders, manually keyed entries). A 02:00 or 06:00 start on the 1st is the conventional buffer.
Common questions
What time does @monthly run?
At 00:00 on the first day of each month, in the cron daemon's timezone — usually UTC on servers. It expands to 0 0 1 * *.
How do I run a job monthly on a different day?
There is no macro for it — set the day-of-month field explicitly. 0 0 15 * * runs at midnight on the 15th; 0 6 2 * * runs at 06:00 on the 2nd. For the last day of the month, Unix cron needs the Quartz/AWS-style L flag or a day-range workaround.
Is @monthly the same as 0 0 1 * *?
Yes, exactly. The macro is expanded before scheduling, so the two forms produce identical run times, logs, and environment.
What is the Quartz or AWS EventBridge equivalent of @monthly?
Quartz: 0 0 0 1 * ? (seconds first, '?' in day-of-week). AWS EventBridge: 0 0 1 * ? * with the trailing year. Macros are not accepted in either dialect, so you always write the fields out.