Back to Blog
Tutorial

AWS Cron Generator: EventBridge Schedule Expressions Made Easy

By CronGen Team

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

  1. Wrapped in cron() – Expressions must start with cron(
  2. Requires year field – 6 fields mandatory (minute, hour, day, month, day-of-week, year)
  3. Uses ? for wildcards – Use ? instead of * for day fields
  4. UTC timezone only – All times are in UTC (use offset calculations)
  5. 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 / minutes
  • hour / hours
  • day / 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:

  1. Use UTC times if possible (no DST issues)
  2. Or create two rules (one for standard time, one for DST) and enable/disable manually
  3. 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

  1. Go to Amazon EventBridge console
  2. Click Create rule
  3. Choose Schedule
  4. Enter cron expression:
    cron(0 9 * * ? *)
    
  5. Select target (Lambda, ECS, SNS, etc.)
  6. 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

  1. Create EventBridge rule with your cron expression
  2. Check "Next 10 trigger times" in the console
  3. Verify they match your expectations

Using AWS CLI

aws events describe-rule --name YourRuleName

Using CronGen

  1. Visit CronGen Decoder
  2. Paste your expression (without cron() wrapper)
  3. See next execution times in UTC
  4. 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

Try CronGen AWS Generator →


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:

  1. Use cron() wrapper for all expressions
  2. Convert to UTC for timezone handling
  3. Use ? for day fields (not *)
  4. Prefer rate() for simple intervals
  5. Test expressions before deploying

Ready to create your AWS cron expression?

Use CronGen AWS Generator →


Related Articles

Related Articles