Cron expression for every 15 minutes
The cron expression */15 * * * *
runs every 15 minutes. The restricted fields are minute */15; the remaining asterisks match anything. That works out to 96 runs per day.
*/15 * * * * Field breakdown
| Field | Value | Meaning |
|---|---|---|
| Minute | */15 | Every 15 minutes, counted from 0: 0, 15, 30, 45 |
| Hour | * | Every hour (0–23) |
| Day of month | * | Every day of the month (1–31) |
| Month | * | Every month (1–12) |
| Day of week | * | Every day of the week (0–6) |
Next runs
- —
- —
- —
- —
- —
Run times are calculated in your browser timezone. The scheduler that executes the job uses its own — always UTC on Vercel Cron, UTC by default on GitHub Actions, the host clock on crontab.
How this schedule works
Cron evaluates the five fields of */15 * * * * — minute, hour, day of month, month, day of week — against the clock once a minute and starts the job on any minute where all five match, which cronstrue reads as "Every 15 minutes": 96 runs per day. Within every hour it fires at :00, :15, :30, :45. Sixty divides by 15 without a remainder, so the gap between runs stays constant as the hour rolls over.
When to use every 15 minutes
A quarter-hour cadence is the usual compromise for imports from an upstream feed, incremental search-index updates, and uptime probes running on a modest budget: 96 runs a day, aligned to clock quarters everyone already reads. It is frequent enough that a stale record is rarely more than fifteen minutes old, and infrequent enough that a run can take several minutes without overlapping the next. Choose it when the data changes on a human timescale rather than a machine one, and when a run that occasionally slips is not an incident.
Common mistakes with every 15 minutes
Fifteen minutes is safe arithmetic — 60 divides by 15 — so the mistakes here are rarely in the expression. They are in what the job assumes. A quarter-hourly import that reads "everything since the last run" will double-process or skip records the first time a run is missed, because cron never tells the job that it missed one. Track a watermark in durable storage and read forward from it, rather than computing "now minus fifteen minutes" from the run clock. The other common slip is putting */15 in the hour field, where it does not mean every fifteen hours in any useful sense.
Platform snippets
The same expression, ready to paste into the four schedulers that read five-field cron. The notes below each snippet are the ones that follow from this schedule; the cron expression generator lists every caveat for every platform.
GitHub Actions
name: Scheduled workflow
on:
schedule:
- cron: '*/15 * * * *'
workflow_dispatch:
jobs:
scheduled:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run job
run: echo "Running scheduled job" Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-cron-job
spec:
schedule: "*/15 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: job
image: my-image:latest
command: ["/bin/sh", "-c", "echo Running"]
restartPolicy: OnFailure Vercel Cron
Hobby plan limitation: cron jobs can only run once per day. Schedules more frequent than daily will fail to deploy on Hobby. Use Pro plan or above for higher frequency.
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [
{
"path": "/api/cron",
"schedule": "*/15 * * * *"
}
]
} - • Pro plan and above: invocations occur within the specified minute (e.g. "5 8 * * *" runs between 08:05:00 and 08:05:59).
crontab
# Edit your crontab: crontab -e
*/15 * * * * /path/to/command
# With logging:
*/15 * * * * /path/to/command >> /var/log/cron.log 2>&1 Variations
-
*/30 * * * *Every 30 minutes Half the runs, at :00 and :30. The obvious step down when a quarter-hourly import keeps finding an empty changeset. -
0,15,30,45 * * * *At 0, 15, 30, and 45 minutes past the hour The identical schedule spelled out. Longer to type, but it states the four fire minutes instead of asking the reader to divide 60 by 15. -
*/15 8-18 * * 1-5Every 15 minutes, between 08:00 AM and 06:59 PM, Monday through Friday Confines the quarter-hourly runs to business hours on weekdays: 44 runs a day rather than 96, with no loss of resolution when anyone is watching. -
*/15 * * * 6,0Every 15 minutes, only on Sunday and Saturday The inverse — quarter-hourly on Saturday and Sunday only. Suits weekend-only reprocessing that would compete with live traffic midweek.
Frequently asked questions
How do I read the cron expression */15 * * * *?
Read the five space-separated fields left to right as minute, hour, day of month, month, and day of week. In */15 * * * * the minute is */15, hour is *, day of month is *, month is *, day of week is *. Of the operators cron defines, this expression uses only the ones that matter here: an asterisk matches every value in its field and a slash introduces a step counted from the start of the field. Put together, cronstrue reads the whole thing as "Every 15 minutes", and a scheduler that checks all five fields once a minute will start the job 96 runs per day.
What timezone does */15 * * * * run in?
Less than you would think. Because the hour field is unrestricted, the cadence is the same in every timezone — 96 runs per day, wherever the scheduler's clock is set. The zone changes the labels on the run times rather than the schedule. It still matters at the edges. GitHub Actions evaluates schedules in UTC unless the workflow adds the optional timezone key beside cron; Vercel Cron is UTC-only; a Kubernetes CronJob follows the kube-controller-manager's zone unless spec.timeZone is set; and a crontab follows the host clock or CRON_TZ. The edge that bites is daylight saving: in a zone that shifts its clocks, the spring-forward hour never arrives and the fall-back hour arrives twice, so a schedule like this one loses or repeats a whole block of runs on those two days a year. Scheduling in UTC avoids it.
Is */15 the same as 0,15,30,45?
The two forms produce exactly the same run times: minute 0, 15, 30, and 45 of every hour. The step form is shorter, and the list form is more explicit — pick whichever your team reads faster. They only diverge when the step does not divide evenly into 60. A step of 15 divides 60 four times with no remainder, so the sequence is uniform; a step such as 45 does not, and */45 fires only at :00 and :45 before restarting at the top of the next hour. When the interval is not a factor of 60, write the list.
Related cron schedules
-
* * * * *Every minute -
*/5 * * * *Every 5 minutes -
*/10 * * * *Every 10 minutes -
*/30 * * * *Every 30 minutes -
0 * * * *Every hour -
0 */2 * * *Every 2 hours
Build a custom schedule in the cron expression generator, or browse every epochkit tool.