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
1in 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 is2in 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 dayMON, which is unambiguous on every platform that accepts cron syntax. - Why is
0 9 * * 1better than@weeklyfor "every Monday"? @weeklyis an alias for0 0 * * 0— midnight on Sunday, NOT Monday. There is no@mondayshortcut in standard Vixie cron. If you want a Monday weekly schedule, you must spell it out:0 9 * * 1or0 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 * 1which 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 cleanercron(0 9 ? * MON#1 *)using the#operator (n-th-weekday-of-month). Quartz also supportsMON#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
Cron expression for every Sunday
The cron expression 0 0 * * 0 runs every Sunday at midnight in Unix cron. AWS uses cron(0 0 ? * 1 *) because Sunday is 1 in AWS, not 0.
Cron expression for every weekday
The cron expression 0 9 * * 1-5 runs at 9 AM Monday through Friday. AWS uses cron(0 9 ? * MON-FRI *) because day-of-week numbering differs.
Cron expression for the first of every month
The cron expression 0 0 1 * * runs at midnight on the 1st of every month. AWS uses cron(0 0 1 * ? *).
Cron expression for the last day of the month
AWS EventBridge supports cron(0 0 L * ? *). Unix cron has no L — use 0 0 28-31 * * with a date -d tomorrow test in the command.
Quartz cron expression generator (7-field syntax)
Build a 7-field Quartz cron expression (seconds, minutes, hours, dom, month, dow, year) with the ? rule and L, W, # operators — for Spring @Scheduled and standalone Quartz.
Cron expression for twice a day
The cron expression 0 6,18 * * * runs twice daily — at 6 AM and 6 PM. The comma syntax lists multiple values for any field.