The cron expression */15 * * * * fires at :00, :15, :30, and :45 every hour, 96 runs per day. Covers why 15 minutes is the default for background jobs.
⏰Every 15 minutes
*Any value,List separator-Range/Step1-5Range 1 through 5*/15Every 15 units*/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.
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:
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.
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.
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.
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.
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.
| 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.
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.
Nothing you paste leaves this tab. Every tool runs entirely in your browser — no upload, no server, no account.