A cron expression that runs every 15 minutes:
*/15 * * * *
This fires at :00, :15, :30, :45 of every hour. Equivalent to:
0,15,30,45 * * * *
The two forms produce identical schedules. The page above generates the schedule; this companion explains how the */15 step operator works and the practical consequences of quarter-hour alignment.
How */15 works
The slash / is the step operator. */15 in the minute field means “every 15 minutes within the field’s range (0–59), starting at the minimum value (0).” So:
*/15 = 0, 15, 30, 45
Note that the step runs from the field’s minimum, not from “now.” The job won’t fire 15 minutes after the daemon starts and then every 15 minutes; it fires at the next aligned 15-minute mark.
The list form 0,15,30,45 produces the same schedule by enumeration. Most engineers prefer */15 for brevity; both are equally valid.
Quarter-hour alignment
All instances run at minutes that are multiples of 15 — specifically :00, :15, :30, :45. This has two consequences:
- Predictability. External monitoring can expect the job to run at quarter-hour marks. Dashboards that show 15-minute buckets line up cleanly with cron’s actual fire times.
- Coordination cost. If many services across an organization use
*/15 * * * *, they all fire at the same four minutes per hour. Database load, API call rates, log ingestion — everything spikes at quarter-hour marks. Stagger by minute (5 */15 * * *for:05, :20, :35, :50) to spread the herd.
Variants and edge cases
5,20,35,50 * * * * ← offset by 5 — same cadence, shifted alignment
*/15 9-17 * * 1-5 ← every 15 min, 9 AM–5 PM, weekdays only
*/15 */2 * * * ← every 15 min, but only every other hour (so 8 fires/day, not 96)
1-59/15 * * * * ← :01, :16, :31, :46 — explicit range with step
The third example is a common mistake: combining steps in the hour and minute fields produces a sparser schedule than people expect.
When */15 isn’t quite right
The step operator divides the field’s full range. */15 in a 0–59 field happens to give clean quarter-hour marks because 60 / 15 = 4 evenly. With a step that doesn’t divide cleanly, the last interval is shorter:
*/14 * * * * ← :00, :14, :28, :42, :56 — then back to :00 (4-minute gap, not 14)
*/13 * * * * ← :00, :13, :26, :39, :52 — then :00 (8-minute gap)
This isn’t a bug — it’s a consequence of the step starting fresh each hour. If you need a true even-interval-across-hour-boundaries schedule, you have to either pick a step that divides 60 (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60) or use a different scheduler.
Use cases that suit 15-minute cadence
- External-data sync (pull from a third-party API every 15 min).
- Cache refresh for content that updates a few times per hour.
- Health checks that ping internal services for staleness.
- Quarter-hourly aggregations (rolling-window metrics).
- Mid-frequency cleanup tasks — too important for hourly, too cheap for every-minute.
For higher-frequency needs, see cron every minute and cron every 5 minutes. For lower-frequency, cron every 30 minutes and cron every hour.
Common pitfalls
- Job duration approaching 15 minutes. If a
*/15job sometimes takes 14 minutes, occasional overruns will overlap with the next run. Wrap withflockor have the job exit early if a previous instance is still running. - Drift in retry-heavy jobs. A job that retries internally for 12 minutes consumes most of its window; the next 15-minute fire gives only 3 minutes of “rest.” For jobs with retries, schedule less frequently than the worst-case duration.
- Misreading
*/15as “every 15 minutes from start.” It’s “every 15 minutes from minute 0 of the hour.” The next fire after restart is the next aligned mark. - Assuming all schedulers parse
*/15. Vixie cron does. Some embedded cron implementations only parse explicit lists — fall back to0,15,30,45if portability matters.
For the broader cron syntax, see the cron expression generator and cron parser.