How to Write a Cron Expression for Every 15 Minutes (*/15 * * * *)
To run a cron job every 15 minutes, use the expression */15 * * * * — the */15 step value in the minute field fires at :00, :15, :30, and :45 past every hour. The remaining four fields stay as wildcards. Build and test it visually with our free Cron Expression Generator.
- The Expression: */15 * * * *
- Cron Every 15 Minutes Syntax, Field by Field
- Crontab Every 15 Minutes: Copy-Paste Examples
- The Step Value Explained: Why */15 Works
- Offset Schedules: Staggering Past the Crowd
- Quartz, GitHub Actions, and systemd Variants
- Testing Before You Trust It
- Three Mistakes That Break 15-Minute Crons
The Expression: */15 * * * *
The cron expression for every 15 minutes is */15 * * * *. Read left to right across the five fields — minute, hour, day of month, month, day of week — it says: at every 15th minute, of every hour, of every day. That produces 4 runs per hour and 96 runs per day, at :00, :15, :30, and :45. If you only need the answer, you can stop here — paste it into your crontab and skip to the testing section. The rest of this guide explains why it works (the step-value mechanic), how to stagger it off the crowd (offset schedules), and how the expression changes in Quartz, GitHub Actions, and systemd, which all speak slightly different dialects of the same idea.
Cron Every 15 Minutes Syntax, Field by Field
Cron every 15 minutes syntax breaks into five fields: minute (0–59) | hour (0–23) | day of month (1–31) | month (1–12) | day of week (0–7, where both 0 and 7 mean Sunday). In */15 * * * *, the first field carries the whole schedule: */15 means “every 15th minute starting from 0.” The other four fields are * (every), so nothing restricts the hour, date, or weekday. Contrast with a common misfire: 15 * * * * (no slash) means “once per hour, at 15 minutes past” — four characters different, 92 fewer runs per day. Another misfire: */15 * * * 1 restricts to Mondays only, because the fifth field stopped being a wildcard. The rule of thumb: every field you don't think about should be *, and any field that isn't * is a restriction you chose on purpose. Our cron expression generator highlights each field as you type, so a stray restriction shows up before it costs you a day of missed runs.
Crontab Every 15 Minutes: Copy-Paste Examples
A crontab entry for every 15 minutes pairs the schedule with a command and logging: */15 * * * * /usr/local/bin/sync.sh >> /var/log/sync.log 2>&1. Three details make this production-ready. First, the absolute path — cron runs with a minimal PATH, so bare command names that work in your shell silently fail at 3 AM; always use full paths for both the script and anything it calls. Second, the log redirect — without >> and 2>&1, output goes to local mail you will never read, and failures vanish. Third, a lock or idempotency guard inside the script, because a job that occasionally runs longer than 15 minutes will overlap with its own next run. Variants: business-hours only is */15 9-17 * * 1-5 (every 15 minutes, 9 AM–5 PM, weekdays); twice-hourly-offset is covered in the staggering section below. After saving with crontab -e, verify the daemon picked it up — on most systems, /var/log/cron or /var/log/syslog shows the next scheduled fire within seconds.
The Step Value Explained: Why */15 Works
The step value is the slash syntax: start-end/step. */15 is shorthand for 0-59/15 — “from minute 0 to minute 59, take every 15th.” That yields 0, 15, 30, 45. The step works in any field: */2 in the hour field is every other hour; */10 in day-of-month is the 1st, 11th, and 21st. Two behaviors worth knowing: the range wraps per-field (there is no “*/90 minutes” — steps can't cross field boundaries, so sub-hourly schedules live in the minute field and multi-hour ones in the hour field), and the start matters — 5-59/15 gives 5, 20, 35, 50, not 0, 15, 30, 45. That offset form is genuinely useful rather than trivia: staggering jobs a few minutes past the quarter hour dodges the thundering-herd moment when thousands of crons fire at :00. If the step mechanic clicks for you here, the same idea with a tighter step powers our most-asked sibling schedule — see how to write a cron expression for every 5 minutes for the */5 version, testing tricks, and the % trap that bites in both.
Offset Schedules: Staggering Past the Crowd
Everyone's cron fires at :00, :15, :30, :45 — including your database's backup, your vendor's webhook retries, and your monitoring checks. Offsetting by a few minutes spreads the load: 7-59/15 * * * * fires at :07, :22, :37, :52. Pick any offset 0–14; odd numbers like 7 or 13 dodge the popular round offsets too. When does offsetting matter? When the job touches a shared resource at a predictable moment — API rate limits that reset on the quarter hour, a database that compacts at :00, or a CI runner pool that fills up on the hour. When doesn't it matter? Purely local jobs (log rotation, temp-file cleanup) can stay on the clean quarter hours; readability beats cleverness there. One caution: document the offset in a comment above the crontab line (“# offset +7 to avoid the :00 API rush”), because six months from now the :07 will look like a typo to whoever inherits the server. Future you is the most frequent victim of unexplained cron offsets.
Quartz, GitHub Actions, and systemd Variants
Not every scheduler speaks five-field cron. Quartz (Java) adds a seconds field first and uses ? as a no-specific-value placeholder: 0 */15 * * * ? — seconds fixed at 0, then the familiar five fields. GitHub Actions uses standard five-field syntax (— */15 * * * *—) in the schedule trigger, but always in UTC and with a minimum practical interval of 5 minutes; scheduled workflows can also lag several minutes during high load, so don't use them for time-critical 15-minute cadences. systemd timers skip cron syntax entirely: OnCalendar=*:0/15 in the .timer unit means every 15 minutes. If you're debugging timestamps in job logs across these systems, remember each one may log in a different timezone — our guide to Unix timestamps and converting epoch times in Excel helps line up log entries when a 15-minute job's output looks like it's from the future.
Testing Before You Trust It
Never deploy a 15-minute schedule untested. The fast loop: temporarily set the minute field to */1 (every minute), watch two or three fires in the logs, confirm the script's actual behavior and runtime — then switch back to */15. What to verify in those test runs: the script found its files (absolute paths!), it wrote to the log (permissions on /var/log), it finished well under 15 minutes (or your overlap guard engaged), and its exit code was 0. Then set a calendar reminder to check the first real day of */15 runs — cron failures are silent by design, and a job that ran fine every minute can still stumble every 15 if it depends on something that changes between runs (a token that expires hourly, a file that only exists after another job). Our cron expression generator shows the next several fire times for any expression, which catches the classic “off-by-one-field” errors before they reach the server.
Three Mistakes That Break 15-Minute Crons
First, the % trap: in a crontab command, an unescaped % means newline — date +%Y-%m-%d inside a crontab line silently splits your command in two. Escape every one as \%. Second, the environment gap: cron's PATH is tiny and it sources no profile, so python3, node, or aws commands that work interactively fail under cron; either export PATH at the top of the crontab or use absolute binary paths. Third, the day-of-month vs day-of-week OR quirk: when both fields are restricted (not *), cron runs when either matches — so */15 * 1 * 1 runs every 15 minutes on the 1st of the month and every Monday, not just Mondays that fall on the 1st. For pure every-15-minutes schedules this quirk never triggers (both fields stay *), but the moment you add a weekday restriction, remember the OR. Fix all three once in a template crontab and every future schedule — including the every-5-minutes version — inherits the protection. And when the job moves files around, our gigabytes to megabytes converter sizes the archives it rotates — the full converter family on our homepage covers every other unit your scripts touch.
Do it in one click
Build and test your cron expression visually — free, no signup.
Open the Free Tool →