Cron expression for every 15 minutes
The cron expression */15 * * * * runs a job every 15 minutes — at :00, :15, :30 and :45 of every hour. Four runs per hour, 96 runs per day. The clock-aligned firing makes it ideal for monitoring pings, cache refreshes and any job that needs to overlap with external systems’ quarter-hour boundaries.
Quick reference
| Platform | Expression |
|---|---|
| Unix / Linux crontab | */15 * * * * |
| Kubernetes CronJob | */15 * * * * |
| GitHub Actions | */15 * * * * |
| AWS EventBridge | cron(0/15 * * * ? *) |
| Quartz (Java) | 0 0/15 * ? * * |
Why is */15 a popular cron interval?
It hits four marks per hour aligned with the natural clock divisions — :00, :15, :30, :45 — which means your job runs at the same minute marks every hour, every day. Three concrete reasons this matters:
- Monitoring pings — Pingdom, UptimeRobot, Better Stack and most monitoring services check at clock-aligned intervals. Aligning your refresh to :15-marks means metrics are fresh when the monitor checks.
- Cache TTL alignment — a 15-minute Redis cache TTL combined with
*/15refresh means the cache is always fresh when read. - Cross-system sync — when two services both run on
*/15, they observe the world at the same moments — easier to debug than offset schedules.
Variations
| Schedule | Expression |
|---|---|
| Every 15 min, business hours only | */15 9-17 * * * |
| Every 15 min, weekdays only | */15 * * * 1-5 |
| Every 15 min on the half-hour offset (:07, :22, :37, :52) | 7-59/15 * * * * |
| Every 15 min in AWS | cron(0/15 * * * ? *) |
| Every 15 min in AWS, weekdays only | cron(0/15 * ? * MON-FRI *) |
How do I use it on each platform?
Linux crontab:
*/15 * * * * /usr/local/bin/refresh-cache
Kubernetes CronJob:
apiVersion: batch/v1
kind: CronJob
metadata:
name: refresh-cache
spec:
schedule: "*/15 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: refresh
image: my-org/refresh-cache:1.0
restartPolicy: OnFailure
AWS EventBridge Scheduler (with timezone):
Type: AWS::Scheduler::Schedule
Properties:
Name: refresh-cache
ScheduleExpression: 'cron(0/15 * * * ? *)'
ScheduleExpressionTimezone: 'UTC'
FlexibleTimeWindow:
Mode: 'OFF'
Target:
Arn: !GetAtt RefreshFunction.Arn
RoleArn: !GetAtt SchedulerRole.Arn
GitHub Actions:
on:
schedule:
- cron: '*/15 * * * *'
Common mistakes
Off-the-quarter offsets are valid but rarely needed. 7-59/15 * * * * runs at :07, :22, :37, :52 — sometimes useful to dodge a thundering herd at :00, but breaks the alignment that makes */15 valuable in the first place.
Confusing */15 with “every 15 minutes after the previous run”. Cron is clock-aligned. If a run takes 16 minutes, the next one starts 1 minute after — overlap is your problem to handle (set concurrencyPolicy: Forbid in K8s, reserve concurrency 1 for Lambda targets).
Assuming AWS rejects */15. Older AWS documentation claims */15 is invalid and only 0/15 works. In practice both forms parse correctly today. Use 0/15 for portability with old IaC, */15 if you prefer the standard form.
For the full AWS ruleset — the ? quirk, # and L operators, CloudFormation and Terraform examples — see the AWS EventBridge cron generator. For the complete Kubernetes manifest with concurrencyPolicy and startingDeadlineSeconds, use the Kubernetes CronJob schedule generator.
For other schedules see common cron schedules, or build a custom expression with the Cron Expression Builder.
Frequently asked questions
- What is the difference between
*/15and0/15? - Both mean "every 15 units starting from 0". Standard Unix cron accepts both. AWS EventBridge prefers
0/15and some older AWS docs even claim*/15is invalid — it actually works in EventBridge today, but0/15is the safer form for AWS-specific docs and IaC examples. - Why might my :00, :15, :30, :45 runs drift over time?
- Cron itself doesn't drift — the controller checks the current minute every cycle and fires when the minute matches. What you might see is small jitter (a few seconds late) because of controller polling intervals or queue backpressure. If runs are minutes late, the controller is overloaded or has been restarted; investigate the controller, not the cron expression.
- Is
*/15aligned with the clock or with cron startup time? - Always with the wall clock.
*/15 * * * *runs at :00, :15, :30, :45 — never at :07, :22, :37, :52. The expression is independent of when cron started or when the rule was created.
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 2 hours
The cron expression 0 */2 * * * runs every 2 hours on the hour — at 00:00, 02:00, 04:00 etc. Step syntax (*/N) works in any field.
Cron expression for every 3 hours
The cron expression 0 */3 * * * runs every 3 hours on the hour — 8 firings per day with no day-boundary gap. Linux/Kubernetes/GitHub Actions; cron(0 */3 * * ? *) in 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 30 seconds
Cron cannot run every 30 seconds — it has no seconds field, only minutes. Use setInterval, KEDA cron-trigger or a long-running scheduler instead.
Cron expression for every 4 hours
The cron expression 0 */4 * * * runs every 4 hours on the hour — at 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00. Six runs per day across Linux, Kubernetes and GitHub Actions; cron(0 */4 * * ? *) in AWS.
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.