FlowingDev

Cron expressions, explained: the time-traveling language of schedulers

Learn how cron expressions, the tiny but mighty language of scheduling, tell computers when to run automated tasks, from backups to newsletters.

Try the tool: Cron Expression Parser

In one sentence

A cron expression is a compact string of characters that defines a recurring schedule, essentially telling a computer when to run an automated task.

The problem it solves

Back in the digital dark ages (the 1970s), if you wanted a computer to do something automatically—say, clean up temporary files at midnight—you had to get creative. You might write a clunky script that ran in a loop, checked the time, and then slept for a while. It was messy, inefficient, and prone to breaking.

Enter cron, a daemon (a background process) born in the Bell Labs halls of early Unix. The name is a nod to Chronos, the Greek personification of time, which is about as geeky as it gets. Cron's job was simple but revolutionary: read a list of commands and the times they should run, and then execute them. It was a "set it and forget it" system for task automation.

To tell cron when to run things, it needed a language. Not a verbose, English-like language, but something a computer could parse instantly. That language is the cron expression. It solves the fundamental problem of how to describe any conceivable recurring schedule—"every Monday at 9 AM," "on the 1st and 15th of every month," "every 10 minutes"—in a standardized, predictable way. Without it, every developer would be reinventing the scheduling wheel, and your server would be a chaotic mess of custom-rolled sleep() commands.

How it works under the hood

A cron expression looks like a string of gibberish to the uninitiated, something like */15 9-17 * * 1-5. But it's not magic; it's a highly structured mini-language. Once you learn the syntax, you can read and write schedules like a pro.

The Five Fields of the Apocalypse (and friends)

A standard cron expression is made of five fields, separated by spaces. Each field represents a unit of time. Think of it as a set of five dials you turn to line up the correct moment.

Field Allowed Values Allowed Special Characters
Minute 0-59 * , - /
Hour 0-23 * , - /
Day of Month 1-31 * , - / ? L W
Month 1-12 or JAN-DEC * , - /
Day of Week 0-7 or SUN-SAT * , - / ? L #

Some modern cron implementations add a sixth field for the year (1970-2099) or even a leading field for seconds (0-59), but the classic five-field format is the most common.

A note on Day of Week: Both 0 and 7 are often accepted for Sunday. Sticking to one convention (like 0=Sun, 6=Sat) is a good idea.

Special Characters: The Secret Language

The real power of cron expressions comes from a handful of special characters that modify the numbers.

  • * (The "every"): This is the wildcard. An asterisk in the Hour field means "every hour of the day." An asterisk in every field (* * * * *) means "every minute of every hour of every day of every month..." You get the picture.

  • , (The "and"): The comma acts as a list separator. 1,15 in the Day of Month field means "on the 1st and the 15th of the month."

  • - (The "through"): The hyphen defines a range. 9-17 in the Hour field means "every hour from 9 AM through 5 PM."

  • / (The "step"): The slash is used to specify increments. */10 in the Minute field means "every 10 minutes." You can combine it with a range, too: 0-30/5 means "every 5 minutes within the first 30 minutes of the hour" (so at :00, :05, :10, :15, :20, :25, :30).

  • ? (The "I don't care"): This one is tricky but important. You can't always specify both a Day of Month and a Day of Week because they can conflict. What happens if you say "run on the 13th of the month and on a Friday," but the 13th falls on a Wednesday? The ? solves this by saying, "I've specified one of these fields, so ignore the other." You'd set the schedule to * * 13 * ? (run on the 13th, I don't care what day of the week it is) or * * ? * 5 (run on every Friday, I don't care what day of the month it is).

  • L (The "last"): L in the Day of Month field means "the last day of the month" (so, Jan 31, Feb 28/29, etc.). In the Day of Week field, it means "the last X of the month." For example, 5L means "the last Friday of the month."

  • W (The "weekday"): 15W in Day of Month means "the nearest weekday to the 15th of the month." If the 15th is a Saturday, the job will run on Friday the 14th. If the 15th is a Sunday, it will run on Monday the 16th.

  • # (The "nth"): This is for finding things like "the third Friday of the month." The expression for that would be * * ? * 5#3.

Putting It All Together

Let's decode a few common expressions:

# Run every night at midnight
0 0 * * *
  • 0 in the minute field: at minute zero (the top of the hour).
  • 0 in the hour field: at hour zero (midnight).
  • * * * in the other fields: every day of every month of every week.
# Run at 8:30 AM every weekday (Mon-Fri)
30 8 * * 1-5
  • 30 in the minute field: at 30 minutes past the hour.
  • 8 in the hour field: at 8 AM.
  • * * for day of month and month: don't care.
  • 1-5 for day of week: on Monday through Friday.
# Run every 15 minutes during business hours (9am-5pm) on weekdays
*/15 9-17 * * 1-5
  • */15: every 15 minutes.
  • 9-17: for hours 9, 10, 11, 12, 13, 14, 15, 16, and 17.
  • 1-5: on Monday through Friday.

Real-world stories

The Case of the Midnight Backup

A startup's database was growing fast. The lead sysadmin knew they needed daily backups, but running the backup script during the day slowed the entire application to a crawl. Users complained, and potential sales were lost. The solution? A simple cron job. She scheduled the resource-intensive backup script to run at 2 AM, when site traffic was practically zero. The expression 0 2 * * * became the silent hero of the company, ensuring their data was safe without disrupting a single user. Lesson: Schedule resource-intensive tasks for off-peak hours to maintain performance.

The Forgotten Newsletter

A small e-commerce site wanted to send a "Weekly Deals" email every Tuesday morning to drive sales. For months, a marketing person named Dave was tasked with manually clicking "Send" at 10 AM. But one week, Dave got sick. The newsletter never went out, and sales for that Tuesday were dismal. The lead developer stepped in and automated the process. She wrote a script to send the newsletter and hooked it up to a cron job: 0 10 * * 2. From then on, the newsletter went out like clockwork, regardless of who was in the office. Lesson: Automate repetitive, time-sensitive tasks to improve reliability and eliminate human error.

The Stale Cache

A news website prided itself on breaking stories, but their homepage often felt slow. Their content was cached for performance, but the cache was only cleared when a developer did it manually. This meant new articles sometimes took hours to appear. A developer set up a cron job to automatically clear and rebuild the site's cache every five minutes. With the expression */5 * * * *, the site became dramatically faster and more up-to-date, as new content was guaranteed to be visible within minutes. Lesson: Use cron for periodic "housekeeping" tasks like cache invalidation to keep systems fresh and performant.

Common mistakes and traps

  • Timezone Troubles: A classic "it runs at the wrong time" problem. Cron jobs almost always run using the server's system time, which might be UTC or some other timezone you're not in. Scheduling a job for 9 AM your time might mean it runs at 2 PM server time. Always be aware of your server's timezone.

  • The Day-of-Month vs. Day-of-Week Clash: A common newbie mistake is to put a value in both the Day-of-Month and Day-of-Week fields (e.g., * * 1 FRI). Most cron daemons interpret this with an OR condition: "run on the 1st of the month OR on any Friday." This is rarely what you want. If you want "the first Friday of the month", you need to use * * ? * 5#1 or a more complex script. Use the ? character to avoid ambiguity.

  • Forgetting Output Redirection: By default, anything your script prints to standard output or standard error gets emailed to the user who owns the crontab. This sounds helpful, but it can quickly fill up a mailbox with useless notifications. Best practice is to explicitly handle output: send it to a log file (>> /var/log/myjob.log 2>&1) or discard it if you don't care (> /dev/null 2>&1).

  • The Overlapping Job: Setting a job to * * * * * means "start a new instance of this job at the beginning of every minute." If your job takes 90 seconds to run, you will have overlapping executions, which can lead to race conditions, resource exhaustion, and all sorts of chaos.

  • The Minimalist Environment: Your interactive shell is full of helpful environment variables like $PATH. A cron job runs in a barren, stripped-down environment. Your script that runs perfectly from the command line might fail in cron because it can't find programs like node or python. The fix is to use absolute paths for all commands (e.g., /usr/bin/node instead of node) or set the PATH variable at the top of your crontab file.

Why it belongs on your radar

You might think cron is just for old-school system administrators, but its DNA is everywhere.

  • Backend & DevOps: It's the de facto standard for scheduling background jobs, from database maintenance and log rotation to deploying code.
  • Web Development: Need to send daily email reports, clear a cache, or generate a sitemap? Cron is your tool.
  • Cloud Platforms: Services like AWS Lambda Scheduled Events and Google Cloud Scheduler use cron expressions to define their triggers. The syntax is a universal language for scheduling, even in the most modern, "serverless" environments.

Learning to read and write cron expressions is a fundamental skill. It's the key that unlocks automation, allowing you to build more robust, reliable, and self-sufficient systems. It’s one of those little things that, once you know it, you'll see opportunities to use it everywhere.

Go deeper

Theory done. Time to get your hands dirty — 100% in your browser.

Try the tool: Cron Expression Parser