The */15 * * * * Expression
*/15 * * * * fires four times per hour (at :00, :15, :30, and :45) for a total of 96 executions per day. The step syntax */15 divides the minute field range (0 to 59) into 15 unit steps starting at 0, yielding exactly four slots per hour that align with clock quarter hours.
This alignment is not coincidental. Quarter hour boundaries map directly to how humans read time and how many SLA windows are defined. A “15 minute check” is both machine efficient and human legible.
Why 15 Minutes Is a Goldilocks Interval
At the extremes, the tradeoffs are obvious: * * * * * runs too often for most jobs, 0 * * * * leaves an hour long gap. The interesting question is where in between the right default lies.
*/5 (12/hour, 288/day) is excellent for anything with a strict SLA or critical path, but it is 3x more expensive than */15 in terms of executions. */10 (6/hour) is a reasonable middle point. */15 wins as a default because:
- 96 runs/day is invisible in most resource budgets. Database connections, API calls, log lines. 96 per day rarely causes noise.
- The 15 minute detection window is acceptable for most noncritical background work. If a sync fails, it retries within 15 minutes. If a metric goes stale, it refreshes within 15 minutes.
- Quarter hour alignment makes log inspection easy. When debugging, filtering logs to the last 15 minute window is intuitive.
Practical Use Cases
Kubernetes CronJobs for internal tasks
K8s CronJob documentation uses */15 as a standard example interval. For periodic cleanup tasks, cache invalidation, or internal health reporting that does not need sub 5 minute freshness, */15 is a reliable default.
CI pipeline scheduled checks
Nightly builds are common but some teams also run a light “smoke test” CronJob on the deploy that fires every 15 minutes. It catches regressions faster than a nightly without the cost of a per commit full suite.
SLA compliance checks
If your SLA window is measured in hours, a 15 minute interval gives you four data points per hour, enough to detect and alert on a breach before the window closes, without generating excessive alert noise.
Data pipeline polling
For ETL pipelines that read from a source system and write to a warehouse, 15 minutes is often the right cadence when the source updates on a similar schedule. Check the source’s update frequency before choosing your interval.
Combining with Hour and Day Restrictions
The power of */15 is how cleanly it combines with other field constraints:
*/15 9-17 * * 1-5 # every 15 min, 9 AM to 5 PM, weekdays only
*/15 * * * 1-5 # every 15 min, 24h, weekdays only
0,15,30,45 8,12,16 * * * # three times a day, on the quarter-hour
*/15 0-6 * * * # every 15 min, overnight hours only (off-peak)
The last example is useful for batch jobs that you want to run frequently but only when the system is lightly loaded: overnight processing windows, off peak data migrations, or jobs that would contend with daytime traffic.
Comparison Table
| Expression | Fires/hour | Fires/day | Max detection lag |
|---|---|---|---|
*/5 * * * * | 12 | 288 | 5 min |
*/10 * * * * | 6 | 144 | 10 min |
*/15 * * * * | 4 | 96 | 15 min |
*/30 * * * * | 2 | 48 | 30 min |
0 * * * * | 1 | 24 | 60 min |
“Max detection lag” is the worst case time between a failure occurring and the next cron run that would detect it. For a 15 minute SLA requirement, */15 is the minimum interval. You need */5 or better to have any margin.
Verifying Execution Times
To see the next 8 execution times for */15 * * * * (two full hours):
from croniter import croniter
from datetime import datetime
cron = croniter("*/15 * * * *", datetime.now())
for _ in range(8):
print(cron.get_next(datetime))
On a system where the crontab is active, confirm the job is running at the expected times:
journalctl -u cron --since "1 hour ago" | grep myjob
You should see exactly 4 entries per hour. If you see fewer, the job may be failing silently. Check your script’s exit code and ensure cron has a valid MAILTO set so errors are reported.