Run a cron job on the 1st of every month with 0 0 1 * * . Monthly report and billing schedule.
The cron expression 0 0 1 * * runs at 00:00 on the 1st of every month. The day-of-month field (1) specifies which calendar days to trigger. This produces 1 execution per month. Monthly schedules are commonly used for billing cycle tasks, subscription renewals, monthly report generation, account statement creation, database archiving, compliance audits, payroll processing, and infrastructure cost reporting. For Quartz Scheduler, use 0 0 1 * ? (swap day-of-month and day-of-week fields, use ? for day-of-week). For AWS EventBridge, use cron(0 0 1 * ? *) (add year field, use ? for day-of-week). For Kubernetes CronJob, use schedule: "0 0 1 * *" directly. Note: months with fewer days than the specified day-of-month will skip that month. For example, day 31 runs only in months with 31 days (7 months out of 12). For the last day of every month, use 0 0 28-31 * * with a script that checks if tomorrow is the 1st. Cron does not natively support "last business day" or "Nth weekday of the month" logic. Implement these rules in your script using date utilities.
The expression 0 0 1 * * means: at minute 0, hour 0, day-of-month 1, month *, day-of-week *. Each field in the cron expression controls a different time component: minute, hour, day of month, month, and day of week.
Run crontab -e in your terminal to open your crontab editor. Add a new line: 0 0 1 * * /path/to/your/script.sh. Save and exit. Verify with crontab -l. Make sure your script is executable (chmod +x script.sh) and uses full paths for all commands.
Quartz Scheduler: 0 0 1 * *. AWS EventBridge: cron(0 0 1 * ? *). Kubernetes CronJob: schedule: "0 0 1 * *" (standard 5-field format). Each platform has slight syntax differences — use our dialect switcher above to get the exact expression.
Cron simply skips that month. For example, day 31 only triggers in months with 31 days (January, March, May, July, August, October, December). February never triggers for days 30-31. Use 0 0 28-31 * * with a script-side check for "last day of month" if you need monthly execution regardless of month length.
Common pitfalls: (1) Cron uses a minimal PATH — always use full paths to commands and scripts. (2) Percent signs (%) must be escaped with backslash in crontab. (3) Cron runs in the system timezone — set CRON_TZ=UTC at the top of your crontab for consistent UTC scheduling. (4) Redirect output to prevent email spam: 0 0 1 * * /path/command >> /var/log/myjob.log 2>&1. (5) Test your cron expression with crontab.guru or our validator above before deploying.
The cron expression 0 0 1 * * has different syntax on various scheduling platforms. Here is the equivalent expression for each:
| Platform | Expression |
|---|---|
| Unix / Linux crontab | 0 0 1 * * |
| Quartz Scheduler (Java) | 0 0 1 * * |
| AWS EventBridge | cron(0 0 1 * ? *) |
| Kubernetes CronJob | 0 0 1 * * |
| Vercel Cron | 0 0 1 * * |
| GitHub Actions | 0 0 1 * * (UTC) |
Key differences across platforms: Quartz uses 7 fields starting with seconds and supports L (last) and W (weekday) modifiers. AWS EventBridge requires a 6th year field and uses ? instead of * in day fields when the other day field is specified. Kubernetes uses standard 5-field Unix cron. Vercel Cron uses the same format but schedules are defined in vercel.json. GitHub Actions uses standard cron but runs in UTC timezone only, so adjust the hour field for your local timezone offset.
Follow these tips when setting up cron jobs in production: