EDT
Everyday Dev Tools
Fast tools, no fuss
Home / Tutorials / Cron Expressions: The Complete Guide to Scheduled Jobs
Date & Time

Cron Expressions: The Complete Guide to Scheduled Jobs

2024-06-20 · 13 min read

Learn how to read, write, and debug cron expressions for scheduling recurring tasks.

What is Cron? And Why I Love It (Despite Its Quirks)

Cron is a time-based job scheduler in Unix-like operating systems. You write a cron expression, and it runs your command on schedule. It's been around since the 1970s, and it's still everywhere — Linux servers, Kubernetes, GitHub Actions, AWS, you name it.

I love cron because it's simple and ubiquitous. But its syntax is famously terse and easy to get wrong. I've seen so many cron bugs in production — usually something that runs at the wrong time, or not at all.

The good news is: Once you understand the pattern, it becomes second nature. And our Cron Generator can help you build and test expressions visually!

Cron Expression Syntax (The 5 Fields You Need to Know)

A standard cron expression has 5 fields, in this order:

* * * * *
│ │ │ │ │
│ │ │ │ └─ Day of week (0-6, 0 = Sunday)
│ │ │ └─── Month (1-12)
│ │ └───── Day of month (1-31)
│ └─────── Hour (0-23)
└───────── Minute (0-59)

Let me repeat the order, because this is where most people mess up: **Minute, Hour, Day of Month, Month, Day of Week.**

Not Month, Day, Year — that's dates, not cron! Not the other way around.

Each field can be:

- `*` — Any value

- A number — Exact value (e.g., `5` in minute field means at 5 minutes past the hour)

- A list — Multiple values separated by commas (e.g., `1,3,5`)

- A range — From X to Y (e.g., `1-5`)

- A step — Every X (e.g., `*/15` in minute field means every 15 minutes)

Let's look at examples to make this concrete!

Common Cron Patterns (My Cheat Sheet)

Here are the cron expressions I've used most often in real systems:

**Every minute:** `* * * * *` (This is almost never what you want!)

**Every hour at 0 minutes:** `0 * * * *`

**Every day at midnight:** `0 0 * * *`

**Every day at 2 AM:** `0 2 * * *`

**Every weekday at 9 AM:** `0 9 * * 1-5`

**Every Sunday at 3 AM:** `0 3 * * 0`

**The 1st of every month at 6 AM:** `0 6 1 * *`

**Every 15 minutes:** `*/15 * * * *`

**Every 4 hours:** `0 */4 * * *`

**Twice a day at 8 AM and 6 PM:** `0 8,18 * * *`

**Mon-Fri at 8:30 AM:** `30 8 * * 1-5`

Save this list — you'll come back to it again and again. And use our Cron Generator to experiment with different schedules and see what they mean!

Day of Week vs Day of Month (The Tricky Corner Case)

Here's the most confusing part of cron: If you specify both day of week and day of month, most cron implementations will run when EITHER matches! This is almost never what you want.

So an expression like `0 0 15 * 0` — 0 minutes, 0 hours, 15th day, any month, Sunday — doesn't mean "the 15th when it's a Sunday." It means "the 15th AND every Sunday!"

If you want something like "the last Friday of the month", standard cron actually can't handle that directly. You either need a cron extension (some systems support additional syntax) or you need to schedule it to run every Friday and check in your script if it's the last one.

My general advice: Avoid specifying both day of week and day of month in the same expression, or make sure you understand exactly how your particular cron implementation handles it!

Cron Time Zones (This Will Surprise You)

Here's a crucial detail many people miss: The cron daemon runs in the system's local time zone!

This means that if your server is in New York, a cron job scheduled at 0 2 * * * will run at 2 AM Eastern Time. If your server is in London, it will run at 2 AM GMT.

This is a good reason to set your servers to UTC! It makes cron predictable.

If you have scheduled jobs for users in different time zones, cron might not be enough — you might need an application-level scheduler that can handle per-user time zones.

Always document what time zone your cron schedules are in! I once had a bug where everyone thought the schedule was in local time, but the server was in UTC — 8 hours off. Not fun.

Debugging Cron Jobs (My Checklist)

Cron jobs have a habit of failing silently. Here's how I debug them:

**1. Does it actually run?**

Add logging to the start of your script. Just a simple "Job started at $(date)" written to a log file.

**2. Is the environment correct?**

Cron has a minimal PATH! Use full paths to executables. Use `which` to find paths.

**3. Is the working directory correct?**

Either use absolute paths for files, or `cd` to the right directory at the start of your script.

**4. Are you catching errors?**

Set up email alerts, or send failed jobs to a monitoring service.

**5. Did you test it?**

Test with a schedule that runs soon (e.g., every minute), verify it works, then change to the real schedule.

And one more pro tip: Use tools like `crontab.guru` or our Cron Generator to verify your expressions before deploying them!

Tools

Try These Tools

Open the tools that go with this tutorial and practice what you learned.

Navigation

Keep Learning