<p>If you've ever stared at <code>*/5 0 1-15 * 1-5</code> and wondered what it actually means, you're not alone. Cron expressions are the backbone of task scheduling on Unix systems, but their compact syntax is notoriously unintuitive.</p>
<p>This guide explains cron expressions from scratch, covers the most common patterns, and introduces a free visual tool that makes building and understanding them trivial.</p>
<h2>What Is a Cron Expression?</h2>
<p>A cron expression is a string that represents a schedule. It uses five space-separated fields:</p>
<pre><code>┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
* * * * *
</code></pre>
<p>Each field accepts specific values and special characters:</p>
<table>
<thead>
<tr>
<th>Character</th>
<th>Meaning</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>*</code></td>
<td>Any value</td>
<td><code>*</code> in hour field = every hour</td>
</tr>
<tr>
<td><code>,</code></td>
<td>List of values</td>
<td><code>1,15,30</code> = minutes 1, 15, and 30</td>
</tr>
<tr>
<td><code>-</code></td>
<td>Range</td>
<td><code>1-5</code> = Monday through Friday</td>
</tr>
<tr>
<td><code>/</code></td>
<td>Step values</td>
<td><code>*/15</code> = every 15 minutes</td>
</tr>
</tbody>
</table>
<h2>The Most Common Cron Patterns</h2>
<h3>Every Minute</h3>
<pre><code>* * * * *
</code></pre>
<p>Runs once every minute. Useful for health checks and polling.</p>
<h3>Every 5 Minutes</h3>
<pre><code>*/5 * * * *
</code></pre>
<p>The workhorse of scheduling. Most monitoring tools use this interval.</p>
<h3>Every Hour at Minute 0</h3>
<pre><code>0 * * * *
</code></pre>
<p>Runs once per hour, at the top of the hour. Good for hourly reports.</p>
<h3>Daily at Midnight</h3>
<pre><code>0 0 * * *
</code></pre>
<p>The classic "run once per day" schedule. Most backup and cleanup tasks use this.</p>
<h3>Weekdays at 9 AM</h3>
<pre><code>0 9 * * 1-5
</code></pre>
<p>Monday through Friday at 9 AM. Perfect for business-hour notifications.</p>
<h3>Every 15 Minutes (Business Hours)</h3>
<pre><code>*/15 9-17 * * 1-5
</code></pre>
<p>Every 15 minutes between 9 AM and 5 PM, Monday through Friday.</p>
<h3>Monthly on the 1st at 3 AM</h3>
<pre><code>0 3 1 * *
</code></pre>
<p>First day of every month at 3 AM. Ideal for monthly reports.</p>
<h2>Special Characters Explained</h2>
<h3>The Asterisk (<code>*</code>)</h3>
<p>The wildcard. In any field, <code>*</code> means "every valid value."</p>
<pre><code>* * * * * → every minute
0 * * * * → every hour (at minute 0)
0 0 * * * → every day (at midnight)
</code></pre>
<h3>The Slash (<code>/</code>)</h3>
<p>Defines steps. <code>N/M</code> means "every M units starting from N."</p>
<pre><code>*/5 * * * * → every 5 minutes (0, 5, 10, 15...)
0 */2 * * * → every 2 hours (0, 2, 4, 6...)
0 0 */3 * * → every 3 days
</code></pre>
<p>Note: <code>*/N</code> in the minute field is NOT the same as <code>N</code> in the hour field. The <code>/</code> operator always creates a step from the minimum value.</p>
<h3>The Comma (<code>,</code>)</h3>
<p>Lists specific values.</p>
<pre><code>0 9,12,15 * * * → at 9 AM, noon, and 3 PM
0 * * * 1,3,5 → every hour on Mon, Wed, Fri
</code></pre>
<h3>The Hyphen (<code>-</code>)</h3>
<p>Defines ranges.</p>
<pre><code>0 9-17 * * * → every hour from 9 AM to 5 PM
0 0 * * 1-5 → midnight Monday through Friday
30 0 1-7 * * → 12:30 AM on the 1st through 7th of each month
</code></pre>
<h2>Building Cron Expressions Visually</h2>
<p>Manual cron expressions are error-prone. A single typo can mean your task runs at the wrong time — or not at all.</p>
<p>I built a <strong>free Cron Expression Builder & Visualizer</strong> that:</p>
<ul>
<li>Lets you select values from dropdown menus (no typing required)</li>
<li>Shows the next 10 execution times in real-time</li>
<li>Generates a human-readable explanation</li>
<li>Supports all standard cron syntax including ranges, lists, and steps</li>
<li>Works entirely in your browser — no server, no tracking, no dependencies</li>
</ul>
<p>Try it here: <a href="https://k1r4.space/cron-builder.html">Cron Expression Builder & Visualizer</a></p>
<h2>Common Mistakes (And How to Avoid Them)</h2>
<h3>1. Confusing Day of Month and Day of Week</h3>
<pre><code>0 0 1 * * → 1st of every month at midnight
0 0 * * 1 → Every Monday at midnight
</code></pre>
<p>Day of month uses 1-31. Day of week uses 0-6 (Sunday=0). They're independent — setting both to specific values creates an AND condition.</p>
<h3>2. Forgetting That Months Start at 1</h3>
<p>In cron, months are 1-12 (not 0-11). January = 1, December = 12. This differs from JavaScript's <code>Date.getMonth()</code> which returns 0-11.</p>
<h3>3. Using 24-Hour Time</h3>
<p>Cron uses 0-23 for hours. There is no AM/PM field. Hour 0 is midnight, hour 12 is noon, hour 23 is 11 PM.</p>
<h3>4. Assuming "/" Works Like Modulo</h3>
<p><code>*/15 * * * *</code> means "at minutes 0, 15, 30, 45" — it starts from 0, not from the current minute. If you need to start at minute 7, use <code>7-59/15</code> (which gives 7, 22, 37, 52).</p>
<h3>5. The "?" Character</h3>
<p>Some cron implementations (like Quartz) use <code>?</code> in the day-of-month or day-of-week fields to mean "no specific value." This is needed when you specify one but not the other, since cron treats both as AND conditions. Standard Unix cron doesn't support <code>?</code>.</p>
<h2>Advanced Patterns</h2>
<h3>Every 10 Minutes, But Only During Business Hours</h3>
<pre><code>*/10 8-17 * * 1-5
</code></pre>
<h3>First Monday of Every Month</h3>
<p>This requires two expressions:</p>
<pre><code>0 9 * * 1 → every Monday at 9 AM
</code></pre>
<p>Then filter in your script to check if it's the first Monday.</p>
<h3>Every 30 Minutes Between 6 AM and 10 PM</h3>
<pre><code>*/30 6-22 * * *
</code></pre>
<h3>Weekends Only</h3>
<pre><code>0 0 * * 0,6
</code></pre>
<h2>Testing Your Cron Expressions</h2>
<p>Before deploying a cron schedule, always test it:</p>
<ol>
<li><strong>Use a visual builder</strong> — see the next execution times</li>
<li><strong>Start with a short interval</strong> — test with <code>*/1 * * * *</code> (every minute) first</li>
<li><strong>Check the timezone</strong> — cron runs in the server's timezone, not yours</li>
<li><strong>Log the output</strong> — always redirect output to a log file</li>
<li><strong>Verify after deployment</strong> — check that the job actually ran at the expected time</li>
</ol>
<h2>A Note on Cron Variants</h2>
<p>Not all cron implementations are the same:</p>
<table>
<thead>
<tr>
<th>Variant</th>
<th>Fields</th>
<th>Special Features</th>
</tr>
</thead>
<tbody>
<tr>
<td>Standard Unix</td>
<td>5</td>
<td>Basic syntax only</td>
</tr>
<tr>
<td>Systemd timers</td>
<td>N/A</td>
<td>Uses INI-style config</td>
</tr>
<tr>
<td>Quartz (Java)</td>
<td>6-7</td>
<td>Supports seconds, <code>?</code>, <code>L</code>, <code>W</code></td>
</tr>
<tr>
<td>AWS EventBridge</td>
<td>6-7</td>
<td>Different syntax entirely</td>
</tr>
<tr>
<td>Kubernetes CronJob</td>
<td>5</td>
<td>Standard cron syntax</td>
</tr>
</tbody>
</table>
<p>Always check your platform's documentation. The tool at k1r4.space covers standard 5-field Unix cron syntax.</p>
<h2>Conclusion</h2>
<p>Cron expressions are powerful but unforgiving. A single character mistake can cause tasks to run at unexpected times or not at all. Using a visual builder eliminates guesswork and lets you verify schedules before deploying them.</p>
<p>The <a href="https://k1r4.space/cron-builder.html">Cron Expression Builder & Visualizer</a> is free, works entirely in your browser, and has zero dependencies. No sign-up, no tracking.</p>
<hr />
<p><em>Found this useful? Bookmark <a href="https://k1r4.space">k1r4.space</a> for more free developer tools — all client-side, all private.</em></p>
← Back to all posts