AWS Cron Generator: EventBridge Schedule Expressions Made Easy
AWS EventBridge (formerly CloudWatch Events) uses a unique cron syntax that differs from both Unix cron and Quartz. This guide shows you exactly how to create schedule expressions for Lambda functions, ECS tasks, and other AWS services.
AWS Cron vs Standard Cron
AWS has TWO ways to schedule events: cron expressions and rate expressions.
| Feature | Unix Cron | AWS Cron | AWS Rate |
|---------|-----------|----------|----------|
| Fields | 5 fields | 6 fields | Simple interval |
| Minimum | 1 minute | 1 minute | 1 minute |
| Syntax | * * * * * | cron(* * * * ? *) | rate(5 minutes) |
| Use case | Specific times | Specific times | Fixed intervals |
AWS Cron Expression Format
AWS cron expressions have 6 required fields:
cron(minute hour day month day-of-week year)
───┬─── ──┬── ─┬─ ──┬── ─────┬───── ──┬──
│ │ │ │ │ │
│ │ │ │ │ └─ 1970-2199
│ │ │ │ └─ 1-7 or SUN-SAT
│ │ │ └─ 1-12 or JAN-DEC
│ │ └─ 1-31
│ └─ 0-23
└─ 0-59
Important Differences from Standard Cron
- Wrapped in
cron()– Expressions must start withcron( - Requires year field – 6 fields mandatory (minute, hour, day, month, day-of-week, year)
- Uses
?for wildcards – Use?instead of*for day fields - UTC timezone only – All times are in UTC (use offset calculations)
- No seconds – Minimum precision is 1 minute
Quick AWS Cron Examples
Every 5 Minutes
cron(0/5 * * * ? *)
Every Hour at :30
cron(30 * * * ? *)
Every Day at 2 AM UTC
cron(0 2 * * ? *)
Every Weekday at 9 AM UTC
cron(0 9 ? * MON-FRI *)
First Day of Every Month
cron(0 0 1 * ? *)
Last Day of Every Month
cron(0 0 L * ? *)
Every Monday at 8 AM UTC
cron(0 8 ? * MON *)
Twice Daily (6 AM and 6 PM UTC)
cron(0 6,18 * * ? *)
Rate Expressions (Simpler Alternative)
For simple recurring schedules, use rate() expressions instead:
rate(value unit)
Valid Units
minute/minuteshour/hoursday/days
Rate Expression Examples
rate(5 minutes) → Every 5 minutes
rate(1 hour) → Every hour
rate(12 hours) → Twice daily
rate(1 day) → Once daily
rate(7 days) → Weekly
When to Use Rate vs Cron
Use rate():
- Simple recurring intervals
- No specific time requirements
- Easy to read and maintain
Use cron():
- Specific times (e.g., "every day at 2 AM")
- Specific days (e.g., "weekdays only")
- Complex schedules (e.g., "first Monday of each month")
Real-World AWS EventBridge Examples
Lambda Function: Daily Backup at 2 AM UTC
Use case: Run a Lambda function to backup RDS database
{
"ScheduleExpression": "cron(0 2 * * ? *)",
"Target": {
"Arn": "arn:aws:lambda:us-east-1:123456789012:function:BackupDB"
}
}
ECS Task: Process Orders Every 15 Minutes
Use case: Run containerized task to process pending orders
rate(15 minutes)
Or specific times during business hours:
cron(0/15 9-17 ? * MON-FRI *)
CloudWatch Alarm: Weekly Health Check
Use case: Check application health every Sunday at midnight UTC
cron(0 0 ? * SUN *)
Step Functions: Monthly Report Generation
Use case: Generate monthly reports on the 1st at 8 AM UTC
cron(0 8 1 * ? *)
SNS Notification: Daily Summary at 5 PM UTC
Use case: Send daily summary email
cron(0 17 * * ? *)
Timezone Handling in AWS
Critical: AWS EventBridge cron expressions run in UTC only.
Converting Local Time to UTC
If you want a job at 9 AM EST (UTC-5):
9 AM EST = 9 + 5 = 14:00 UTC
cron(0 14 * * ? *)
If you want 6 PM PST (UTC-8):
6 PM PST = 18 + 8 = 02:00 UTC (next day)
cron(0 2 * * ? *)
Daylight Saving Time (DST)
Problem: UTC doesn't observe DST, but local times do.
Solution:
- Use UTC times if possible (no DST issues)
- Or create two rules (one for standard time, one for DST) and enable/disable manually
- Or use Lambda to calculate dynamic schedules
Special Characters in AWS Cron
* (All Values)
cron(0 * * * ? *) → Every hour
? (No Specific Value)
Required for day-of-month OR day-of-week (must use ? for one)
cron(0 9 ? * MON *) → Every Monday (don't care about day-of-month)
cron(0 9 15 * ? *) → 15th of every month (don't care about day-of-week)
, (List of Values)
cron(0 9,12,15 * * ? *) → 9 AM, 12 PM, 3 PM
cron(0 9 ? * MON,WED,FRI *) → Monday, Wednesday, Friday
- (Range)
cron(0 9-17 * * ? *) → Every hour from 9 AM to 5 PM
cron(0 9 ? * MON-FRI *) → Weekdays only
/ (Increments)
cron(0/5 * * * ? *) → Every 5 minutes
cron(0 0/2 * * ? *) → Every 2 hours
L (Last)
cron(0 0 L * ? *) → Last day of every month
cron(0 0 ? * 6L *) → Last Friday of every month
cron(0 0 L-3 * ? *) → 3 days before end of month
W (Weekday)
cron(0 0 15W * ? *) → Nearest weekday to the 15th
# (Nth Occurrence)
cron(0 9 ? * 2#1 *) → First Monday of every month
cron(0 9 ? * 6#3 *) → Third Friday of every month
Common AWS Cron Patterns
Business Hours (9 AM - 5 PM UTC, Weekdays)
cron(0 9-17 ? * MON-FRI *)
Every 30 Minutes
cron(0/30 * * * ? *)
Or simpler:
rate(30 minutes)
Daily at Midnight UTC
cron(0 0 * * ? *)
Weekly on Sunday at 2 AM UTC
cron(0 2 ? * SUN *)
Monthly on the 1st at 8 AM UTC
cron(0 8 1 * ? *)
Quarterly (Jan, Apr, Jul, Oct) at Noon UTC
cron(0 12 1 1,4,7,10 ? *)
Every 6 Hours
cron(0 0/6 * * ? *)
Or:
rate(6 hours)
Last Friday of Month at 5 PM UTC
cron(0 17 ? * 6L *)
Setting Up EventBridge Rules
Using AWS Console
- Go to Amazon EventBridge console
- Click Create rule
- Choose Schedule
- Enter cron expression:
cron(0 9 * * ? *) - Select target (Lambda, ECS, SNS, etc.)
- Create rule
Using AWS CLI
aws events put-rule \
--name DailyBackup \
--schedule-expression "cron(0 2 * * ? *)" \
--state ENABLED
Add Lambda target:
aws events put-targets \
--rule DailyBackup \
--targets "Id"="1","Arn"="arn:aws:lambda:us-east-1:123456789012:function:BackupDB"
Using CloudFormation
Resources:
DailyBackupRule:
Type: AWS::Events::Rule
Properties:
Description: "Trigger backup Lambda daily at 2 AM UTC"
ScheduleExpression: "cron(0 2 * * ? *)"
State: ENABLED
Targets:
- Arn: !GetAtt BackupLambda.Arn
Id: "BackupTarget"
Using Terraform
resource "aws_cloudwatch_event_rule" "daily_backup" {
name = "daily-backup"
description = "Trigger backup daily at 2 AM UTC"
schedule_expression = "cron(0 2 * * ? *)"
}
resource "aws_cloudwatch_event_target" "lambda" {
rule = aws_cloudwatch_event_rule.daily_backup.name
target_id = "BackupLambda"
arn = aws_lambda_function.backup.arn
}
Using AWS CDK (TypeScript)
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
const rule = new events.Rule(this, 'DailyBackup', {
schedule: events.Schedule.cron({
minute: '0',
hour: '2',
day: '*',
month: '*',
weekDay: '?',
year: '*'
})
});
rule.addTarget(new targets.LambdaFunction(backupLambda));
Common Mistakes and Fixes
❌ Wrong: Missing cron() Wrapper
0 2 * * ? *
✅ Correct: Use cron() Function
cron(0 2 * * ? *)
❌ Wrong: Using Both Day Fields with *
cron(0 9 * * * *)
Error: Can't use * for both day-of-month and day-of-week
✅ Correct: Use ? for One
cron(0 9 * * ? *) ← Every day
cron(0 9 ? * MON *) ← Every Monday
❌ Wrong: Including Seconds
cron(0 0 2 * * ? *)
Error: AWS cron doesn't support seconds
✅ Correct: Start with Minutes
cron(0 2 * * ? *)
❌ Wrong: Forgetting UTC Conversion
cron(0 9 * * ? *) ← Thinking this is 9 AM local time
✅ Correct: Convert to UTC
cron(0 14 * * ? *) ← 9 AM EST = 14:00 UTC
Testing Your AWS Cron Expression
Using AWS Console
- Create EventBridge rule with your cron expression
- Check "Next 10 trigger times" in the console
- Verify they match your expectations
Using AWS CLI
aws events describe-rule --name YourRuleName
Using CronGen
- Visit CronGen Decoder
- Paste your expression (without
cron()wrapper) - See next execution times in UTC
- Adjust if needed
Best Practices
1. Use Rate Expressions for Simple Schedules
Instead of:
cron(0/15 * * * ? *)
Use:
rate(15 minutes)
Easier to read and less error-prone.
2. Document Timezone Conversions
Add comments in your IaC:
# Runs at 9 AM EST (14:00 UTC)
ScheduleExpression: "cron(0 14 * * ? *)"
3. Avoid Overlapping Executions
If a job takes 10 minutes, don't run it every 5 minutes:
rate(5 minutes) ← Bad if job takes 10 min
Use:
rate(15 minutes) ← Safe buffer
4. Distribute Load
Don't run all jobs at midnight:
cron(0 0 * * ? *) ← Heavy load at midnight
Spread them out:
cron(0 1 * * ? *) ← Job 1 at 1 AM
cron(0 2 * * ? *) ← Job 2 at 2 AM
cron(0 3 * * ? *) ← Job 3 at 3 AM
5. Use CloudWatch Logs
Enable logging for your Lambda/ECS tasks to debug scheduling issues.
Cost Considerations
EventBridge Pricing
- Free tier: 14 million invocations/month
- After free tier: $1.00 per million events
Example Costs
Every 5 minutes:
- Invocations/month: 288/day × 30 = 8,640
- Cost: Free (well under 14M limit)
Every minute:
- Invocations/month: 1,440/day × 30 = 43,200
- Cost: Free
Multiple rules running every minute:
- 100 rules × 43,200 invocations = 4,320,000
- Cost: Free (still under 14M)
Most use cases stay within free tier indefinitely.
Monitoring and Debugging
Check EventBridge Metrics (CloudWatch)
aws cloudwatch get-metric-statistics \
--namespace AWS/Events \
--metric-name Invocations \
--dimensions Name=RuleName,Value=DailyBackup \
--start-time 2025-12-01T00:00:00Z \
--end-time 2025-12-10T00:00:00Z \
--period 3600 \
--statistics Sum
Enable CloudWatch Logs
For Lambda targets, check logs:
aws logs tail /aws/lambda/BackupDB --follow
Set Up Alarms
Alert if rule stops firing:
FailedInvocationsAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
MetricName: FailedInvocations
Namespace: AWS/Events
Statistic: Sum
Period: 3600
EvaluationPeriods: 1
Threshold: 1
AlarmActions:
- !Ref SNSAlertTopic
Advanced Patterns
Conditional Execution
Use Lambda to check conditions before running:
import boto3
import os
from datetime import datetime
def lambda_handler(event, context):
# Only run if it's a business day
if datetime.now().weekday() >= 5: # Saturday or Sunday
print("Skipping: Weekend")
return
# Run actual job
run_backup()
Dynamic Schedules
Update EventBridge rules programmatically:
import boto3
events = boto3.client('events')
# Enable rule during business hours
events.enable_rule(Name='BusinessHoursRule')
# Disable at night
events.disable_rule(Name='NightRule')
Multi-Region Scheduling
Deploy same rule in multiple regions for redundancy:
# us-east-1
ScheduleExpression: "cron(0 2 * * ? *)"
# eu-west-1 (same time, different region)
ScheduleExpression: "cron(0 2 * * ? *)"
📊 Processing data with your cron jobs? Railway offers zero-config PostgreSQL, MySQL, and Redis with automatic backups. $5 free credit monthly - perfect for automated data pipelines.
Free AWS Cron Expression Generator
Creating AWS EventBridge cron expressions manually is tedious. Use CronGen to:
- ✅ Generate valid AWS cron expressions visually
- ✅ See next execution times in UTC
- ✅ Convert between rate() and cron() formats
- ✅ Handle timezone conversions automatically
- ✅ Copy-paste directly into EventBridge, CloudFormation, or Terraform
Frequently Asked Questions
Can I use timezones other than UTC?
No, AWS EventBridge only supports UTC. You must convert local times to UTC manually.
What's the minimum schedule interval?
1 minute for both cron() and rate() expressions.
Can I schedule for seconds?
No, AWS EventBridge doesn't support seconds-level precision. Use Lambda with EventBridge Scheduler (newer service) for sub-minute scheduling.
What happens if my Lambda takes longer than the schedule interval?
EventBridge will invoke again on schedule, even if previous invocation is still running. Use Lambda reserved concurrency or SQS to prevent overlaps.
How do I run something every 90 minutes?
Use rate():
rate(90 minutes)
Cron expressions can't handle intervals that don't divide evenly into an hour.
Conclusion
AWS EventBridge cron expressions are powerful but require understanding key differences:
- Use
cron()wrapper for all expressions - Convert to UTC for timezone handling
- Use
?for day fields (not*) - Prefer
rate()for simple intervals - Test expressions before deploying
Ready to create your AWS cron expression?