Skip to main content
C
CodeUtil

Cron Expression Examples: Copy-Paste Schedules for Linux, AWS & Kubernetes

Ready-to-use cron expressions for every common task: every minute, hourly, daily at midnight, weekly, monthly, weekdays only, and more. Includes Unix crontab, AWS EventBridge, GitHub Actions, and Kubernetes CronJob formats.

2024-05-0210 min
Related toolCron Generator

Use the tool alongside this guide for hands-on practice.

The cron cheat sheet I wish I had years ago

I've been writing cron expressions for over a decade now, and I still catch myself double-checking the field order. Is it minute-hour-day or hour-minute-day? (It's minute first, always.) After one too many 3 AM pager alerts from misconfigured schedules at Šikulovi s.r.o., I started keeping a personal cheat sheet. This is that cheat sheet, battle-tested and ready to copy-paste.

Here's the thing about cron: the syntax is simple once you internalize it, but getting it wrong can be expensive. I once scheduled a cleanup job to run every minute instead of every hour because I put the asterisk in the wrong field. That's 60x the database load. Not fun. So bookmark this, and let's make sure your schedules actually do what you think they do.

The five fields you need to memorize

Standard cron has 5 fields, read left to right: minute (0-59), hour (0-23), day of month (1-31), month (1-12), day of week (0-6 where Sunday is 0). I remember it as 'minutes matter most' - minute comes first. Special characters: * means any, */n means every n, n-m is a range, n,m is a list.

# ┌───────────── minute (0-59)
# │ ┌───────────── hour (0-23)
# │ │ ┌───────────── day of month (1-31)
# │ │ │ ┌───────────── month (1-12)
# │ │ │ │ ┌───────────── day of week (0-6, Sun=0)
# │ │ │ │ │
# * * * * *

  0 9 * * *      # 9:00 AM every day
  */15 * * * *   # Every 15 minutes
  0 0 1 * *      # Midnight on the 1st of each month

Every minute (use with caution)

Running something every minute sounds harmless until you realize that's 1,440 executions per day. I use this for critical health checks only. If your script takes more than a minute to run, you'll have overlapping executions - been there, debugged that.

  • * * * * * = Every minute
  • */1 * * * * = Same thing, just more explicit
  • Good for: Health checks, queue workers, real-time monitoring
  • Watch out for: System overload, overlapping runs, log spam

Every 5, 10, 15, or 30 minutes

These are my go-to intervals for most polling tasks. */5 is great for cache refreshes, */15 for API syncs. Pro tip: if you're checking an external API, don't pick an exact interval like */10 - add some randomness or offset to avoid hammering their servers at the same time as everyone else.

  • */5 * * * * = Every 5 minutes (my default for most things)
  • */10 * * * * = Every 10 minutes
  • */15 * * * * = Every quarter hour
  • */30 * * * * = Every half hour
  • 0,30 * * * * = Exactly at :00 and :30 (subtly different - runs at fixed times)

Hourly jobs

Hourly is where I put log rotation, lightweight reports, and data syncs. The key decision is: do you want minute 0 (top of the hour) or some offset? I prefer offsets like :15 or :30 to spread load and avoid the 'thundering herd' problem where everyone's cron jobs fire at :00.

  • 0 * * * * = Top of every hour
  • 30 * * * * = Half past every hour (my preference)
  • 0 */2 * * * = Every 2 hours
  • 0 */3 * * * = Every 3 hours
  • 0 */6 * * * = Every 6 hours (4 times daily)

Daily jobs

Most of my cron jobs run daily. Backups go at 2 AM, reports at 6 AM before the team wakes up. I avoid midnight exactly because every dev and their dog schedules things at 0 0 * * *. Spreading things out to 2 AM, 3 AM, 4 AM keeps the server happy.

  • 0 0 * * * = Midnight (crowded hour - I avoid this)
  • 0 2 * * * = 2 AM (my backup time)
  • 0 6 * * * = 6 AM (morning reports)
  • 0 9 * * * = 9 AM (business day start)
  • 30 4 * * * = 4:30 AM (offset to avoid pile-ups)

Multiple times per day

When something needs to run a few times daily, I use comma-separated hours. The 9,17 pattern (9 AM and 5 PM) is classic for notifications. For business hours coverage, the range syntax 9-17 gives you every hour during work time.

  • 0 9,17 * * * = 9 AM and 5 PM (start and end of day)
  • 0 8,12,18 * * * = Three times daily
  • 0 9-17 * * * = Every hour 9 AM to 5 PM
  • */30 9-17 * * * = Every 30 min during business hours

Weekly jobs

Weekly reports, maintenance windows, end-of-week summaries - these all go here. I schedule heavy maintenance for Saturday or Sunday nights. Quick tip: day 0 is Sunday, day 1 is Monday. I always have to look this up. Always.

  • 0 0 * * 0 = Sunday midnight
  • 0 0 * * 1 = Monday midnight
  • 0 9 * * 1 = Monday 9 AM (weekly standup reminder)
  • 0 18 * * 5 = Friday 6 PM (weekly summary)
  • 0 2 * * 6 = Saturday 2 AM (maintenance window)

Weekdays only

Most business logic only needs to run Monday through Friday. The 1-5 range in the weekday field is your friend here. I use this for all customer-facing notifications - nobody wants an automated email at 3 AM on Saturday.

  • 0 9 * * 1-5 = 9 AM Mon-Fri
  • 0 0 * * 1-5 = Midnight on weekdays
  • 0 0 * * 6,0 = Midnight on weekends only
  • 0 8-18 * * 1-5 = Business hours, weekdays only

Monthly jobs

Billing, invoices, monthly reports, archive jobs - these run on the 1st. Sometimes I'll also do a mid-month run on the 15th for certain metrics. If you need 'last day of month', that's tricky - standard cron doesn't support it directly. You'll need a script that checks the date.

  • 0 0 1 * * = Midnight on the 1st
  • 0 9 1 * * = 9 AM on the 1st (monthly report)
  • 0 0 15 * * = Mid-month (the 15th)
  • 0 0 1,15 * * = 1st and 15th
  • 0 2 1 * * = 2 AM on the 1st (monthly backup)

Specific day of month

Payroll, billing cycles, subscription renewals - these often have fixed dates. The L character for 'last day' is supported in some systems (Quartz, AWS) but not standard cron. For first-Monday-of-month type schedules, you need to get creative with 1-7 combined with weekday.

  • 0 0 5 * * = 5th of every month
  • 0 0 10 * * = 10th of every month
  • 0 0 25 * * = 25th (common payday)
  • 0 9 L * * = Last day of month (where L is supported)
  • 0 0 1-7 * 1 = First Monday of month

Quarterly and yearly

Quarterly financial reports run on the 1st of January, April, July, October. For annual jobs like license renewals or year-end processing, you set a specific month and day. These are rare but when you need them, here they are.

  • 0 0 1 1,4,7,10 * = Quarterly (1st of each quarter)
  • 0 9 1 */3 * = Every 3 months at 9 AM
  • 0 0 1 1 * = January 1st (annual job)
  • 0 0 31 12 * = December 31st (year-end)
  • 0 0 15 4 * = April 15th (tax deadline, if you're in the US)

My database maintenance schedule

Here's what I actually run for database maintenance at Šikulovi s.r.o.. Stagger your jobs by 30-60 minutes so they don't compete for resources. I learned this the hard way when backup and vacuum ran simultaneously and the server ground to a halt.

  • 0 2 * * * = Daily backup at 2 AM
  • 0 3 * * 0 = Weekly full backup Sunday 3 AM
  • 0 1 * * * = Daily vacuum/optimize at 1 AM
  • 30 2 * * * = Reindex at 2:30 AM (after backup starts)
  • 0 4 1 * * = Monthly archive on the 1st at 4 AM

Log cleanup (don't skip this)

I've seen servers die because nobody cleaned up logs. Set up rotation and cleanup early, before your disk fills up at 3 AM on a holiday weekend. Trust me on this one.

  • 0 0 * * * = Daily log rotation at midnight
  • 0 3 * * * = Daily temp file cleanup
  • 0 4 * * 0 = Weekly log archive
  • 0 5 1 * * = Monthly old backup removal

Monitoring schedules

Health checks and monitoring need to balance frequency against overhead. Critical services get every-minute checks, everything else gets 5-minute intervals. Daily summary emails go out in the morning before standup.

  • * * * * * = Every minute (critical services only)
  • */5 * * * * = Every 5 min (standard health check)
  • 0 * * * * = Hourly metrics rollup
  • 0 9 * * 1-5 = Weekday morning alert digest

CI/CD schedules

Nightly builds, security scans, dependency updates - these are scheduled to run during off-hours so they don't slow down developer machines or consume CI resources during the day.

  • 0 0 * * * = Nightly build
  • 0 6 * * 1-5 = Morning build before work
  • 0 2 * * 0 = Weekly dependency update (Sunday)
  • 0 3 * * * = Daily security scan

AWS and Kubernetes gotchas

Different platforms have different cron formats. AWS EventBridge adds a 6th field (year) and uses ? as a placeholder. Kubernetes uses standard 5-field but watch your timezone - it defaults to the controller's timezone, not UTC. GitHub Actions is always UTC, no configuration possible.

  • Kubernetes: Standard 5-field, controller timezone by default
  • GitHub Actions: 5-field, always UTC, minimum 5-minute intervals
  • Google Cloud Scheduler: Standard 5-field with timezone support
# AWS EventBridge (6 fields with year)
cron(0 9 * * ? *)

# GitHub Actions
on:
  schedule:
    - cron: '0 9 * * 1-5'

# Kubernetes CronJob
spec:
  schedule: "*/5 * * * *"

Timezone headaches

I run everything in UTC now. Daylight saving time has bitten me too many times - jobs that skip or double-run because 2:30 AM doesn't exist or exists twice during DST transitions. Just use UTC and convert in your application code. Future you will thank present you.

  • Document your timezone in a comment above each cron entry
  • UTC avoids all DST problems
  • 2:30 AM local time is dangerous during DST changes
  • Kubernetes: Use timeZone field in CronJob spec (v1.25+)

Test before you deploy

I built the Cron Generator tool specifically because I was tired of deploying cron jobs and waiting to see if they ran correctly. Always preview the next few run times before pushing to production. Check edge cases like the 31st of the month or February 29th. A few minutes of testing saves hours of debugging why your job didn't run.

FAQ

What is the cron expression for running every day at midnight?

Use 0 0 * * * to run at midnight (00:00) every day. The first 0 is the minute, the second 0 is the hour, and the asterisks mean every day of month, every month, and every day of week.

How do I run a cron job every 5 minutes?

Use */5 * * * * to run every 5 minutes. The */5 in the minute field means every 5th minute. You can use the same pattern for other intervals like */10, */15, or */30.

How do I schedule a cron job only on weekdays?

Use 1-5 in the day-of-week field (the 5th field). For example, 0 9 * * 1-5 runs at 9:00 AM Monday through Friday. Days are numbered 0-6 where 0 is Sunday.

What is the cron expression for the first day of every month?

Use 0 0 1 * * to run at midnight on the 1st of every month. Change the first two numbers to adjust the time, for example 0 9 1 * * for 9:00 AM on the 1st.

Can I run a cron job on the last day of the month?

Standard cron does not support "last day" directly. Some systems support L in the day field (0 0 L * *). Alternatively, use a script that checks if tomorrow is the 1st before running.

How do I run a job at multiple specific times?

Use comma-separated values. For example, 0 9,12,18 * * * runs at 9:00 AM, 12:00 PM, and 6:00 PM daily. You can combine this with ranges: 0 8-17 * * 1-5 runs every hour from 8 AM to 5 PM on weekdays.

What is the difference between day of month and day of week?

Day of month (field 3) specifies dates 1-31. Day of week (field 5) specifies 0-6 (Sunday-Saturday). If both are set to non-asterisk values, the job runs when either condition matches, not both.

How do I avoid cron job overlaps?

For long-running jobs, use a lock file or flock command to prevent overlapping executions. For example: flock -n /tmp/myjob.lock /path/to/script.sh will skip if the previous run is still active.

Martin Šikula

Founder of CodeUtil. Web developer building tools I actually use. When I'm not coding, I experiment with productivity techniques (with mixed success).

Related articles