AWS Lambda Scheduled Events vs Cron Jobs: When to Use Each
AWS Lambda with EventBridge can run code on a schedule without managing servers. But is it actually the right choice for your scheduled tasks? This guide breaks down the real trade-offs between Lambda schedules, traditional crontab, and external cron services so you can pick the right tool for each job.
How AWS Lambda Scheduled Events Work
AWS does not have a standalone "cron service." Instead, you combine two services: Amazon EventBridge (formerly CloudWatch Events) creates a rule that fires on a schedule, and AWS Lambda executes your code when the rule triggers. EventBridge acts as the scheduler; Lambda acts as the worker.
The setup flow looks like this: you create an EventBridge rule with a schedule expression, point it at a Lambda function as the target, and deploy. AWS handles the rest. No EC2 instances, no crontab files, no daemon to keep alive.
There are two types of schedule expressions in EventBridge, and understanding the difference matters.
rate() vs cron() Expressions in EventBridge
EventBridge supports two scheduling syntaxes. They look similar but behave differently.
The rate() Expression
The simpler option. It defines a fixed interval between invocations:
rate(5 minutes) # Every 5 minutes rate(1 hour) # Every hour rate(7 days) # Every 7 days
The first execution starts relative to when you create or update the rule, not at any specific clock time. If you create a rate(1 hour) rule at 2:37 PM, it fires at 3:37, 4:37, 5:37, and so on. There is no way to anchor it to a specific minute.
The cron() Expression
For precise scheduling. AWS uses a six-field cron format, which differs from the standard five-field Unix format:
# AWS EventBridge cron (6 fields): cron(minute hour day-of-month month day-of-week year) # Standard Unix cron (5 fields): minute hour day-of-month month day-of-week # Examples: cron(0 9 * * ? *) # 9:00 AM UTC daily cron(0 18 ? * MON-FRI *) # 6:00 PM UTC weekdays cron(0 0 1 * ? *) # Midnight on the 1st of each month
| Difference | Unix cron | AWS EventBridge cron() |
|---|---|---|
| Fields | 5 | 6 (adds year) |
| Day-of-week | 0-6 (Sun=0) | 1-7 (Sun=1) or SUN-SAT |
| ? wildcard | Not supported | Required in day-of-month or day-of-week |
| Timezone | System timezone | UTC only (EventBridge Scheduler supports TZ) |
The ? wildcard is a common source of errors. You must use it in either the day-of-month or day-of-week field (but not both). It means "no specific value" and tells EventBridge to ignore that field. If you use * in both, the rule will fail to save.
If you find AWS cron syntax confusing, you are not alone. Our cron expression generator outputs standard 5-field expressions that work with CronJobPro, traditional crontab, and most other scheduling tools.
Lambda Timeout and Execution Limits
Lambda functions have a hard limit of 15 minutes per invocation. If your scheduled task takes longer than that, Lambda will kill the process mid-execution. There is no way to extend this limit.
Other limits worth knowing:
| Limit | Value | Impact on Scheduled Tasks |
|---|---|---|
| Max execution time | 900 seconds | Long-running jobs must be split into chunks |
| Memory | 128 MB – 10 GB | Memory-intensive tasks get expensive fast |
| Deployment size | 50 MB zipped | Large dependencies may not fit |
| /tmp storage | 512 MB – 10 GB | Temp files are wiped between invocations |
| Concurrent executions | 1,000 default | Scheduled jobs compete with API handlers |
That concurrency limit is particularly important. If you run 50 API-triggered Lambda functions and 10 scheduled Lambda functions in the same account, they share the same pool. A burst of API traffic can throttle your scheduled jobs or vice versa.
Cold Starts: The Hidden Latency
When Lambda has not run a function recently, it needs to provision a new execution environment. This is called a cold start, and it adds latency before your code actually begins running.
Cold start times depend on runtime, deployment size, and whether you are inside a VPC:
| Runtime | Typical Cold Start | In VPC |
|---|---|---|
| Python | 100–300 ms | +200–500 ms |
| Node.js | 100–300 ms | +200–500 ms |
| Java / .NET | 500 ms – 5 s | +200–500 ms |
| Docker image | 1–10 s | +200–500 ms |
For scheduled tasks that run hourly or less frequently, cold starts are virtually guaranteed because Lambda recycles idle environments after roughly 5-15 minutes of inactivity. A function scheduled to run once per day will cold-start every single time.
You can mitigate this with Provisioned Concurrency, which keeps warm environments ready. But it costs $0.0000041667 per GB-second of provisioned concurrency, which means you are paying 24/7 even when the function only runs once a day. At that point, you are losing the cost advantage of serverless.
Pricing: What Lambda Scheduled Jobs Actually Cost
Lambda pricing has three components for scheduled tasks: request charges, compute charges, and EventBridge charges (free for schedule rules).
# Lambda pricing (us-east-1, March 2026): Requests: $0.20 per 1M invocations Compute: $0.0000166667 per GB-second Free tier: 1M requests + 400,000 GB-seconds / month # Example: Run a 256 MB function for 10 seconds, every 15 minutes Invocations: 4 × 24 × 30 = 2,880 / month Compute: 2,880 × 10s × 0.25 GB = 7,200 GB-seconds Cost: ~$0.12 / month (within free tier for first year) # Example: 20 scheduled functions, 512 MB, 30s each, every 5 minutes Invocations: 20 × 12 × 24 × 30 = 172,800 / month Compute: 172,800 × 30s × 0.5 GB = 2,592,000 GB-seconds Cost: ~$43.20 / month (no free tier left)
For a handful of lightweight jobs, Lambda is effectively free. But costs scale surprisingly fast when you add more functions, increase memory, or extend execution times. And this does not include CloudWatch Logs costs (typically $0.50/GB ingested), which can exceed the Lambda compute cost if your functions produce verbose output.
For comparison: CronJobPro's Pro plan at €3.99/month includes 50 scheduled jobs with monitoring, retries, and notifications built in. No Lambda configuration, no IAM policies, no CloudWatch costs. For HTTP-based scheduled tasks, it is significantly simpler and often cheaper than the Lambda approach. See pricing.
Error Handling and Retry Behavior
When EventBridge triggers a Lambda function and the invocation fails, the retry behavior depends on the invocation type. EventBridge uses asynchronous invocation, which means:
- Lambda retries the function twice on failure (configurable to 0, 1, or 2 retries).
- There is a delay between retries (typically 1 minute for the first retry, then longer). The exact timing is not guaranteed.
- After all retries are exhausted, the event is discarded unless you have configured a dead-letter queue (SQS or SNS).
- If the function succeeds but returns an error in the response body, Lambda does not retry. You need to throw an exception or return a non-200 status for retries to kick in.
Setting up proper error handling requires configuring Lambda destination on failure, CloudWatch alarms for error metrics, and potentially an SNS topic for notifications. Each of these is a separate AWS service with its own configuration.
Monitoring with CloudWatch
Every Lambda invocation automatically sends logs to CloudWatch Logs and metrics to CloudWatch Metrics. The key metrics for scheduled tasks are:
# Useful CloudWatch metrics for scheduled Lambda:
Invocations # Total number of times the function ran
Errors # Invocations that resulted in a function error
Throttles # Invocations that were throttled (concurrency limit)
Duration # How long the function ran (ms)
ConcurrentExec # Number of simultaneous executions
# CloudWatch alarm example (Terraform):
resource "aws_cloudwatch_metric_alarm" "lambda_errors" {
alarm_name = "scheduled-job-errors"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "Errors"
namespace = "AWS/Lambda"
period = 300
statistic = "Sum"
threshold = 0
alarm_actions = [aws_sns_topic.alerts.arn]
dimensions = {
FunctionName = aws_lambda_function.scheduled_job.function_name
}
}Setting this up properly means creating CloudWatch alarms, SNS topics, and subscription endpoints for each function. It works, but the configuration overhead is significant compared to a service that includes monitoring by default.
When Lambda Wins
Lambda scheduled events are the right choice in specific situations:
- You are already deep in AWS. If your entire stack is on AWS and your team knows CloudFormation or CDK, adding an EventBridge rule is just a few lines of infrastructure code.
- The task needs AWS SDK access. If your scheduled job processes S3 objects, queries DynamoDB, or publishes to SQS, Lambda is the natural fit because the IAM role grants direct access.
- The task is compute-heavy. Data transformation, image processing, or ML inference that needs CPU and memory rather than just an HTTP call.
- You need sub-minute frequency. With Step Functions or custom polling, Lambda can execute at intervals shorter than one minute, though this gets complex.
When Traditional Cron or an External Service Wins
Lambda is not the best choice for every scheduled task. An external cron service like CronJobPro, or even a plain crontab, is often more practical:
- Your task is an HTTP endpoint. If the work is already exposed as a web endpoint (an API route, a webhook handler, a health check), wrapping it in a Lambda function adds unnecessary complexity. Just schedule the HTTP call directly.
- You want monitoring without building it. Lambda plus CloudWatch plus SNS requires gluing three services together. A purpose-built cron service includes execution history, failure alerts, and dashboards out of the box.
- Your team is not on AWS. If you host on Vercel, Railway, DigitalOcean, or your own servers, adding an AWS account just for scheduled tasks introduces operational overhead and vendor coupling.
- Tasks run longer than 15 minutes. Database migrations, large file processing, or batch operations that need 30+ minutes cannot run in Lambda at all.
- You want timezone support. Standard EventBridge rules run in UTC only. EventBridge Scheduler (a newer service) supports timezones but adds more configuration.
Step-by-Step: Setting Up a Lambda Scheduled Event
If you decide Lambda is the right tool, here is how to set it up. This example uses the AWS CLI, but the same configuration applies in CloudFormation, CDK, or Terraform.
# 1. Create the Lambda function aws lambda create-function \ --function-name daily-cleanup \ --runtime python3.12 \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::123456789:role/lambda-exec-role \ --zip-file fileb://function.zip \ --timeout 300 \ --memory-size 256 # 2. Create the EventBridge rule with a cron schedule aws events put-rule \ --name daily-cleanup-schedule \ --schedule-expression "cron(0 3 * * ? *)" \ --description "Run daily cleanup at 3 AM UTC" # 3. Grant EventBridge permission to invoke the function aws lambda add-permission \ --function-name daily-cleanup \ --statement-id eventbridge-invoke \ --action lambda:InvokeFunction \ --principal events.amazonaws.com \ --source-arn arn:aws:events:us-east-1:123456789:rule/daily-cleanup-schedule # 4. Add the Lambda function as the rule target aws events put-targets \ --rule daily-cleanup-schedule \ --targets "Id"="1","Arn"="arn:aws:lambda:us-east-1:123456789:function:daily-cleanup"
That is four CLI commands with ARNs, IAM permissions, and target configurations. Compare this to scheduling the same task with an external cron service: enter a URL, pick a schedule, and save.
Side-by-Side Comparison
| Factor | Lambda + EventBridge | External Cron Service |
|---|---|---|
| Setup time | 15–60 min (IAM, function, rule, permissions) | 2 minutes |
| Monitoring | Build it yourself (CloudWatch + SNS) | Built-in dashboard + alerts |
| Max duration | 15 min | Depends on your endpoint (no limit) |
| Timezone | UTC (Scheduler supports TZ) | Any timezone per job |
| Cost (10 daily jobs) | ~$0 (free tier) to ~$5/mo | €3.99/mo (CronJobPro Pro) |
| Best for | Compute tasks inside AWS | HTTP-based scheduled tasks |
The Bottom Line
AWS Lambda scheduled events are a solid option when your tasks need direct access to AWS resources and your team is comfortable with the configuration overhead. For everything else, particularly HTTP-based scheduled tasks, an external cron service removes the operational complexity while adding monitoring, retries, and notifications that would take hours to replicate in AWS.
If your scheduled tasks boil down to "call this URL every X minutes," you do not need Lambda. You need a scheduler with built-in reliability. And if you are already using cron expressions, you can browse common patterns or build custom expressions to get started in seconds.
Related Articles
Schedule serverless functions on Vercel with cron expressions.
GitHub Actions Scheduled WorkflowsAutomate CI/CD and maintenance tasks on a schedule with GitHub Actions.
Cron Job Monitoring Best PracticesStrategies for monitoring scheduled tasks across any platform.
Node.js Cron Jobs GuideSchedule tasks in Node.js applications with BullMQ and node-cron.
Skip the Lambda boilerplate
Schedule HTTP requests with monitoring, retries, and Slack/email notifications. No AWS configuration required. Free for up to 5 jobs.