Cron syntax cheat sheet: crontab, GitHub Actions, Kubernetes
Cron syntax with tested expressions, the day-of-week trap, and how time zones and limits differ in crontab, GitHub Actions, Kubernetes and Laravel in 2026.
7 min read

In this article
Five fields separated by spaces decide when your backups run, your invoices go out and your caches clear. Cron syntax looks simple, but the same expression can behave differently in a Linux crontab, GitHub Actions, Kubernetes and a framework scheduler, mainly because of time zones and one surprising rule about days.
This cheat sheet gives you the syntax, a table of tested expressions, the differences between the platforms developers use most in October 2026, and a short checklist for running scheduled jobs safely. Every expression in the tables was evaluated with a cron parser on 9 October 2026, and the platform rules come from each project's own documentation.

The five fields
┌───────────── minute (0-59)
│ ┌─────────── hour (0-23)
│ │ ┌───────── day of month (1-31)
│ │ │ ┌─────── month (1-12 or jan-dec)
│ │ │ │ ┌───── day of week (0-7 or sun-sat; 0 and 7 are Sunday)
│ │ │ │ │
* * * * * command| Symbol | Meaning | Example |
|---|---|---|
* | Every value | * * * * * runs every minute |
, | A list | 0 9,17 * * * runs at 09:00 and 17:00 |
- | A range | 30 9 * * 1-5 runs at 09:30 on weekdays |
/ | A step | */15 * * * * runs every 15 minutes |
| Names | First three letters, case-insensitive | 5 4 * * sun runs at 04:05 on Sundays |
The cronie crontab(5) manual (the cron used by Fedora and Red Hat-family systems) notes that steps only work within their own field: */35 in the minute field runs at minutes 0 and 35 of every hour, not every 35 minutes. Kubernetes documents day-of-week as 0-6; use 0 rather than 7 for Sunday if your schedule might move between systems.
Tested expressions you can copy
Next run times below were calculated from 10:00 UTC on Friday 9 October 2026.
| Expression | Meaning | Next runs |
|---|---|---|
*/15 * * * * | Every 15 minutes | 10:15, 10:30, 10:45, 11:00 |
0 */6 * * * | Every six hours, on the hour | 12:00, 18:00, 00:00, 06:00 |
0 2 * * * | Daily at 02:00 | 10 Oct 02:00, 11 Oct 02:00 ... |
30 9 * * 1-5 | Weekdays at 09:30 | Mon 12 Oct, Tue 13 Oct ... |
0 22 * * 1-5 | Weekdays at 22:00 | Fri 9 Oct, Mon 12 Oct ... |
0 0 * * 0 | Sundays at midnight | 11 Oct, 18 Oct, 25 Oct ... |
0 3 1,15 * * | 1st and 15th at 03:00 | 15 Oct, 1 Nov, 15 Nov ... |
0 0 1 * * | First day of each month | 1 Nov, 1 Dec, 1 Jan ... |
Shortcut strings
| Macro | Equivalent | Notes |
|---|---|---|
@hourly | 0 * * * * | |
@daily / @midnight | 0 0 * * * | @midnight is listed by Kubernetes; check before using elsewhere |
@weekly | 0 0 * * 0 | |
@monthly | 0 0 1 * * | |
@yearly / @annually | 0 0 1 1 * | |
@reboot | At daemon start-up | Crontab only; no meaning in GitHub Actions or Kubernetes |
The day-of-month and day-of-week trap
If both day fields are restricted, cron runs the job when either matches, not when both do. The cronie manual states this explicitly. So 0 9 1-7 * 1 does not mean "the first Monday of the month". It means "days 1 to 7, and also every Monday". Our parser confirmed it: from 9 October 2026, the next runs were Monday 12, Monday 19 and Monday 26 October, then Sunday 1 November.
To run on the first Monday, schedule 0 9 * * 1 and check the date inside the job:
# crontab: run on Mondays, continue only if the day of month is 1-7
0 9 * * 1 [ "$(date +\%d)" -le 07 ] && /usr/local/bin/monthly-reportNote the backslash before %. In a crontab, an unescaped % is turned into a newline and the rest of the line is passed to the command as standard input, a classic source of jobs that "run but do nothing".

How each platform differs
| Platform | Default time zone | Setting a time zone | Other rules |
|---|---|---|---|
| Linux crontab (cronie) | The system's local time | CRON_TZ=Asia/Kolkata line in the crontab | SHELL defaults to /bin/sh; set MAILTO or output is mailed to the owner |
GitHub Actions schedule | UTC | timezone: key with an IANA name | Minimum interval 5 minutes; runs on the default branch; may be delayed under load |
| Kubernetes CronJob | kube-controller-manager's local time | .spec.timeZone (stable since v1.27) | CRON_TZ or TZ inside the schedule is rejected |
| Laravel scheduler | Application time zone | ->timezone() or schedule_timezone | One crontab entry runs schedule:run every minute |
Linux crontab
crontab -e # edit your crontab
crontab -l # list it
# Example crontab
MAILTO=ops@example.com
CRON_TZ=Asia/Kolkata
15 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1Cron runs with a minimal environment, so use absolute paths for commands and files. CRON_TZ is supported by cronie; other cron implementations differ, so check man 5 crontab on your server.
GitHub Actions
GitHub's workflow syntax uses POSIX cron, defaults to UTC, and now accepts an optional IANA time zone:
on:
schedule:
- cron: '30 5 * * 1-5'
timezone: "America/New_York"Three rules from GitHub's documentation matter in practice. The shortest interval is once every 5 minutes. Scheduled runs can be delayed during high load, and the start of every hour is a busy time, so pick an odd minute such as 17. And in a public repository, scheduled workflows are disabled automatically after 60 days without repository activity. For time zones with daylight saving time, GitHub says runs in a skipped hour move to the next valid time (a 02:30 run becomes 03:00).
Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
spec:
schedule: "15 2 * * *"
timeZone: "Etc/UTC"
concurrencyPolicy: Forbid # skip a run if the previous one is still going
startingDeadlineSeconds: 200 # give up if it cannot start within 200 s
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: registry.example.com/report:1.4.2concurrencyPolicy accepts Allow (the default), Forbid and Replace. Without timeZone, schedules follow the controller manager's local time, which on managed clusters you may not control.
Laravel's scheduler
Laravel keeps schedules in code (routes/console.php) and needs one cron entry on the server:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1Its documentation lists helpers such as ->withoutOverlapping() and ->onOneServer(), and php artisan schedule:list shows the next run of every task. Laravel's own advice on time zones is worth repeating for every platform: when daylight saving time changes, a task may run twice or not at all, so avoid time zone scheduling when possible.
Free tools for writing and checking expressions
- crontab.guru by Cronitor translates an expression into plain English as you type. Why this resource: the fastest way to sanity-check a schedule in a code review.
man 5 crontabon the actual server. Why: it documents the cron implementation you really run, including which extensions it supports.- A parser in your test suite. For Node.js, the
cron-parserpackage can list upcoming run times. Why: a unit test catches the day-of-week trap before production does.
// npm install cron-parser (we used v5.10.2)
import { CronExpressionParser } from 'cron-parser';
const it = CronExpressionParser.parse('0 9 1-7 * 1', {
currentDate: new Date('2026-10-09T10:00:00Z'),
tz: 'UTC',
});
console.log(it.take(4).map((d) => d.toISOString()));
// Mondays 12, 19, 26 Oct and Sunday 1 Nov: day fields are OR-edA checklist for scheduled jobs
- Write the time zone down next to every schedule, and prefer UTC for anything that must run exactly once.
- Avoid 01:00 to 03:00 local time in zones with daylight saving time.
- Prevent overlaps:
concurrencyPolicy: Forbid, Laravel'swithoutOverlapping(), orflock -n /tmp/job.lock commandon Linux. - Make jobs idempotent, so a duplicate or retried run does no harm.
- Log output and alert on failure; a silent cron job is the one that stopped weeks ago.
- Spread load: do not schedule everything at
0 * * * *.
Frequently asked questions
What does */5 * * * * mean?
Every five minutes: at minutes 0, 5, 10 and so on, of every hour, every day.
Why does my first-Monday schedule run every Monday?
When both day-of-month and day-of-week are restricted, cron runs when either matches. Schedule every Monday and check the date inside the job instead.
Which time zone do GitHub Actions schedules use?
UTC by default. GitHub's workflow syntax now accepts an optional
timezonekey with an IANA name, such asAmerica/New_York.What is the shortest interval for a GitHub Actions schedule?
Once every 5 minutes, and runs may be delayed during high load, especially at the start of each hour.
Can I put CRON_TZ in a Kubernetes CronJob schedule?
No. Kubernetes rejects
CRON_TZorTZin.spec.schedule; use the.spec.timeZonefield, stable since v1.27.Why does my cron command with % fail?
In a crontab, an unescaped
%becomes a newline and the rest is sent to standard input. Escape it as\%, for example indate +\%F.
Your next customer could start right here.
Introduce your tool, product or business to readers exploring technology.
Explore placements and request a private quote
Sources
- crontab(5) manual page (cronie) — man7.org / cronie
- Events that trigger workflows: schedule — GitHub Docs
- Workflow syntax: on.schedule — GitHub Docs
- CronJob — Kubernetes
- Laravel 13.x: Task Scheduling — Laravel
- crontab guru — Cronitor
Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.
Comments
No comments yet. Be the first to join the conversation.
Leave a comment
Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.
More from Cloudsoft Zone

Resource guideResources
Official documentation worth bookmarking for PHP, JavaScript and Node.js developers
A checked list of primary references for web developers: MDN, web.dev, the PHP manual and support schedule, Node.js API docs and releases, TypeScript, Laravel, React and WordPress docs, OWASP Cheat Sheets, DevDocs and endoflife.date.
By Cloudsoft Zone

ComparisonResources
Student developer programmes in 2026: GitHub Education, Azure, JetBrains, AWS and Google
What students actually get from GitHub Education, Azure for Students, JetBrains educational licences, AWS Educate and Google Cloud for students, who qualifies, how to verify without an academic email, and what to watch out for.
By Cloudsoft Zone

Laravel
Upgrading from Laravel 12 to Laravel 13: a practical guide
Laravel 12 lost bug-fix support in August 2026. This guide covers the PHP 8.3 requirement, Composer changes, the CSRF middleware rename, cache and session hardening, low-impact changes that often bite, and a safe rollout plan.
By Cloudsoft Zone
