Cron expression for every Monday
The cron expression 0 9 * * 1 runs a job every Monday at 9 AM in Unix cron. The trailing 1 is the day-of-week — Monday in Vixie cron’s 0-based numbering (where Sunday is 0). Monday weekly schedules are typical for sprint kickoffs, weekly digests, and “start of the work week” reports. AWS EventBridge uses cron(0 9 ? * MON *) or cron(0 9 ? * 2 *) because AWS numbers days 1–7 starting Sunday, so Monday is 2.
Quick reference
| Platform | Expression | Monday number |
|---|---|---|
| Unix / Linux crontab | 0 9 * * 1 or 0 9 * * MON | 1 |
| Kubernetes CronJob | 0 9 * * 1 | 1 |
| GitHub Actions | 0 9 * * 1 | 1 |
| AWS EventBridge | cron(0 9 ? * MON *) or cron(0 9 ? * 2 *) | 2 (named: MON) |
| Quartz (Java) | 0 0 9 ? * MON | 2 (named: MON) |
Why is Monday 1 in Unix but 2 in AWS?
Same reason Sunday is 0 in Unix and 1 in AWS — the two numbering schemes start their week on Sunday but use different starting indexes. Vixie cron is 0-based (Sun=0, Mon=1, …, Sat=6). AWS EventBridge inherits Java Calendar’s 1-based numbering (Sun=1, Mon=2, …, Sat=7).
So when porting Monday schedules between Unix and AWS:
Unix: 0 9 * * 1 # Monday 9 AM
AWS: cron(0 9 ? * 2 *) # same Monday 9 AM, different number
AWS: cron(0 9 ? * MON *) # same — recommended portable form
Use the named day (MON) whenever possible — it’s unambiguous on every cron flavor that supports cron syntax (Linux, Kubernetes, AWS, Quartz, GitHub Actions, anacron). Numeric day-of-week is the most common bug source when migrating between schedulers.
Variations
| Schedule | Expression |
|---|---|
| Every Monday at 9 AM | 0 9 * * 1 |
| Every Monday at midnight | 0 0 * * 1 |
| Every Monday at 8:30 AM (start-of-day reports) | 30 8 * * 1 |
| Every Monday and Thursday at 9 AM | 0 9 * * 1,4 |
| Every Monday EXCEPT public holidays | (cron can’t — wrap with a holiday-check command) |
| First Monday of every month at 9 AM (Unix trick) | 0 9 1-7 * 1 |
| First Monday of every month (AWS) | cron(0 9 ? * MON#1 *) |
| Last Monday of every month (AWS) | cron(0 9 ? * MONL *) |
| Every Monday in AWS | cron(0 9 ? * MON *) |
How do I use it on each platform?
Linux crontab:
0 9 * * 1 /usr/local/bin/weekly-digest
Or with the named day for readability:
0 9 * * MON /usr/local/bin/weekly-digest
Kubernetes CronJob:
apiVersion: batch/v1
kind: CronJob
metadata:
name: weekly-digest
spec:
schedule: "0 9 * * 1"
timeZone: "America/New_York" # ensure 9 AM is local 9 AM
jobTemplate:
spec:
template:
spec:
containers:
- name: digest
image: my-org/weekly-digest:1.0
restartPolicy: OnFailure
A “Monday at 9 AM” schedule is meaningful only relative to a real timezone — UTC 9 AM is 4 AM Eastern, which is not “start of the work week” anywhere. Always set timeZone (Kubernetes 1.25+) or AWS’s ScheduleExpressionTimezone for human-aligned weekday schedules.
AWS EventBridge Scheduler:
Type: AWS::Scheduler::Schedule
Properties:
Name: weekly-digest
ScheduleExpression: 'cron(0 9 ? * MON *)'
ScheduleExpressionTimezone: 'America/New_York'
FlexibleTimeWindow:
Mode: 'OFF'
Target:
Arn: !GetAtt DigestFunction.Arn
RoleArn: !GetAtt SchedulerRole.Arn
GitHub Actions:
on:
schedule:
- cron: '0 9 * * 1' # 9 AM UTC every Monday
GitHub Actions only supports UTC cron — there’s no per-workflow timezone option. For Monday digests intended for a US East team, you’d write 0 13 * * 1 (13 UTC = 9 AM EDT, 8 AM EST). Pick one offset and live with the daylight-saving drift, or move the workflow to a self-hosted runner with timezone control.
Common mistakes
Confusing 1 (Monday) with 1 (January) in different fields. The fields are positional: minute, hour, dom, month, dow. 0 9 * 1 * is “9 AM every day in January”, not “9 AM every Monday”. The day-of-week field is the fifth, after month.
Using MON in old AWS docs. Older EventBridge documentation used a numeric-only convention; some IaC validators (especially CloudFormation pre-2019) would reject cron(0 9 ? * MON *). Modern AWS accepts MON. If your linter complains, fall back to 2.
Assuming @weekly means Monday. It doesn’t — @weekly is 0 0 * * 0, midnight Sunday. There’s no @monday alias. Spell out Monday schedules explicitly.
The “first Monday” trap. 0 9 1 * 1 does NOT mean “first Monday of the month” — Vixie cron treats dom and dow as a logical OR (any day-of-month=1 OR any Monday). The schedule fires on the 1st of every month AND every Monday — way more often than intended. The 1-7 * 1 trick relies on Monday-of-the-first-week always being one specific day; AWS’s MON#1 is the explicit form.
For other schedules see common cron schedules, or build a custom expression with the Cron Expression Builder.
Frequently asked questions
- Is Monday `1` in both Unix and AWS, unlike Sunday?
- Yes — Monday is one of the few days where the numbering aligns. Vixie cron numbers days 0–6 starting Sunday, so Monday is `1`. AWS EventBridge and Quartz use 1–7 starting Sunday, so Monday is `2` in their numeric scheme — wait, that's not aligned. Actually, the numeric values diverge for every day: Unix Monday=1 vs AWS Monday=2. The portable form is the named day `MON`, which is unambiguous on every platform that accepts cron syntax.
- Why is `0 9 * * 1` better than `@weekly` for "every Monday"?
- `@weekly` is an alias for `0 0 * * 0` — midnight on Sunday, NOT Monday. There is no `@monday` shortcut in standard Vixie cron. If you want a Monday weekly schedule, you must spell it out: `0 9 * * 1` or `0 9 * * MON`. The same trap exists for `@daily` (midnight UTC) and `@hourly` (top of the hour) — convenient when they match what you want, misleading when they don't.
- How do I run on the first Monday of every month?
- Cron alone can't directly express "first Monday" — there's no nth-occurrence operator in Vixie cron. The trick is `0 9 1-7 * 1` which fires on any day in the 1st–7th that is also a Monday — guaranteed to be exactly one such day per month. AWS EventBridge supports the cleaner `cron(0 9 ? * MON#1 *)` using the `#` operator (n-th-weekday-of-month). Quartz also supports `MON#1`.
Need a different schedule?
Build cron expressions for Unix, Kubernetes, AWS EventBridge and Quartz — with a human-readable description and the next 5 run times.
Open the Cron Expression Builder →Related
What is a cron job?
A cron job is a scheduled command that runs at fixed times on Unix-like systems. The schedule is a one-line cron expression of five space-separated fields.
Cron expression for every 5 minutes
The cron expression `*/5 * * * *` runs every 5 minutes in Linux crontab, Kubernetes, GitHub Actions; `cron(*/5 * * * ? *)` in AWS EventBridge.
Cron expression for every 15 minutes
The cron expression `*/15 * * * *` runs every 15 minutes — at :00, :15, :30, :45 — across Linux, Kubernetes, GitHub Actions and AWS.
Cron expression for every 30 minutes
The cron expression `*/30 * * * *` runs every 30 minutes — at :00 and :30 of every hour. Same in Linux, Kubernetes and GitHub Actions; `cron(*/30 * * * ? *)` in AWS.
Cron expression for every hour
The cron expression `0 * * * *` runs once per hour on the hour. Same syntax in Linux, Kubernetes and GitHub Actions; `cron(0 * * * ? *)` in AWS EventBridge.
Cron expression for daily at midnight
The cron expression `0 0 * * *` runs once daily at midnight. Watch the timezone — Kubernetes < 1.25 and AWS EventBridge default to UTC, not local time.