Cron Job Syntax Explained: The Complete 2026 Guide for Developers
Author
Muhammad Awais
Published
May 23, 2026
Reading Time
9 min read
Views
18k

Why Cron Syntax Trips Up Every Developer (And How to Fix That)
You have seen it before. A scheduled task that was supposed to run every Monday at 9 AM fires every minute instead. Or a database cleanup job that should run once a month somehow never runs at all. The culprit is almost always the same thing: a misread cron expression. Cron job syntax has been around since 1975 and powers millions of scheduled tasks across every server and platform in existence today. Yet the documentation for it has barely improved since the 1990s. Most guides still show the classic five-field table and leave you to figure out the rest. This guide covers everything a working developer actually needs to know in 2026: the full syntax, every special character, real-world examples, and how cron scheduling works specifically on Vercel, Node.js, and BullMQ.
The Five Fields: What Each Position Controls
A standard cron expression has five fields separated by spaces. Each field controls one unit of time, and they always appear in the same order. Reading from left to right: minute, hour, day of month, month, day of week. A sixth field for seconds exists in some implementations but is not part of the original Unix cron standard.
Here is what each position means and the valid values it accepts:
Minute (0–59): The minute within the hour when the job runs. A value of
30means the job triggers at the 30-minute mark of any matching hour.Hour (0–23): The hour in 24-hour format. A value of
14means 2 PM. A value of0means midnight. This field trips up a lot of developers who try to use 12-hour AM/PM notation cron only understands 24-hour time.Day of Month (1–31): The specific day within a calendar month. A value of
1runs the job on the first of every matching month.Month (1–12): The calendar month. Some implementations also accept three-letter abbreviations like
JAN,FEB, and so on, but using numbers is safer across platforms.Day of Week (0–7): The day of the week, where both
0and7represent Sunday. Monday is1, Saturday is6. Some platforms use only 0–6.
The asterisk * in any field means "every valid value for this field." A cron expression of * * * * * runs every single minute. That is the expression to test with when you are checking if a cron runner is working and the one to immediately replace once you have confirmed it.
Special Characters That Change Everything
The five fields alone only get you to simple schedules. The real power and most of the confusion comes from the special characters that let you express complex timing rules.
Asterisk
*: Every value: Matches all valid values for a field.* * * * *runs every minute of every hour of every day.Comma
,: List of values: Lets you specify multiple values.0 9,17 * * *runs at 9 AM and 5 PM every day.0 0 * * 1,3,5runs at midnight on Monday, Wednesday, and Friday.Hyphen
-: Range of values: Specifies a continuous range.0 9-17 * * *runs at the top of every hour from 9 AM through 5 PM.0 0 1-15 * *runs at midnight every day for the first half of the month.Slash
/: Step values: This is the one most developers get wrong. The slash means "every N" within the context of the field it appears in.*/15 * * * *runs every 15 minutes.0 */2 * * *runs every two hours on the hour.*/5 8-18 * * 1-5runs every five minutes between 8 AM and 6 PM on weekdays.Question mark
?: No specific value (non-standard): Used in some cron implementations like Quartz Scheduler to indicate "any" in the day-of-month or day-of-week fields when the other field is already specified. You will see this in Java-based systems and some cloud schedulers but it is not part of standard Unix cron.
If you want to generate and validate expressions without mentally working through each field, our free cron job generator lets you build any schedule visually and shows you exactly when the next five executions will fire — before you deploy anything.
⚡ Try the Free Cron Job Generator — Build Any Schedule Instantly
30 Real Cron Expressions Developers Actually Use
Abstract syntax rules only go so far. The fastest way to understand cron is to read real expressions paired with plain English explanations. Here are the patterns that come up constantly in production applications:
* * * * *: Every minute. Used for health checks and testing only.*/5 * * * *: Every 5 minutes. Common for polling external APIs.*/15 * * * *: Every 15 minutes. Cache warming, metrics collection.0 * * * *: Every hour on the hour. Hourly report generation.0 */2 * * *: Every 2 hours. Rate limit resets, session cleanup.0 0 * * *: Every day at midnight UTC. Daily database backups, log rotation.0 1 * * *: Every day at 1 AM. Nightly email digests sent when user traffic is lowest.0 9 * * *: Every day at 9 AM. Morning notification jobs.0 9 * * 1: Every Monday at 9 AM. Weekly summary emails.0 0 * * 1: Every Monday at midnight. Weekly stats rollups.0 9 * * 1-5: Weekdays at 9 AM. Business-hours-only tasks.0 0,12 * * *: Midnight and noon daily. Twice-daily syncs.0 0 1 * *: First day of every month at midnight. Monthly invoice generation.0 0 15 * *: 15th of every month. Mid-month billing cycles.0 0 1 1 *: January 1st at midnight. Annual data archiving.30 4 1,15 * *: 4:30 AM on the 1st and 15th of each month.0 0 * * 0: Every Sunday at midnight. Weekly cache clear.*/30 9-17 * * 1-5: Every 30 minutes during business hours on weekdays.0 8-18 * * 1-5: Every hour from 8 AM to 6 PM on weekdays.0 0 * * 1,4: Every Monday and Thursday at midnight.
Vercel Cron Jobs: What Actually Works in 2026
Vercel introduced built-in cron job support as a stable feature and it has become the default scheduling solution for teams already deploying Next.js on the platform. The setup is straightforward: you create a Route Handler at any path you choose inside the app/api directory, then register it in your vercel.json file with a cron expression and the path to trigger.
The Vercel cron system sends a GET request to your Route Handler on the schedule you specify. It adds a special authorization header that you should verify inside the handler to prevent the endpoint from being triggered by external requests. Without this check, anyone who discovers your cron URL can manually trigger your scheduled task. Vercel's documentation recommends checking that the Authorization header matches Bearer followed by your CRON_SECRET environment variable.
There is an important limitation to understand: Vercel's free Hobby plan allows one cron job with a minimum interval of once per day. The Pro plan allows up to 40 cron jobs with a minimum interval of once per minute. If your application needs more frequent scheduling or a higher number of jobs, you need the paid plan or a self-hosted alternative.
One thing many developers miss: Vercel cron jobs always fire in UTC. If you want a job to run at 9 AM Eastern Time, you need to add 4 or 5 hours depending on the time of year and use 0 13 * * * or 0 14 * * * respectively. Debugging timezone mismatches is one of the most common Vercel cron complaints always confirm which timezone your platform is using before assuming the schedule is wrong.
Security in cron jobs deserves the same attention you give to any other API endpoint. Our guide on Next.js rate limiting and bot protection covers the broader authentication patterns that apply directly to securing your scheduled endpoints.
Node.js Cron Jobs: node-cron vs BullMQ vs Bree
For applications running on a persistent server a VPS, a container, or a long-running Node.js process you have more options than Vercel's HTTP-based approach, and the trade-offs between them matter significantly at scale.
node-cron is the most widely used option for simple use cases. It hooks into the Node.js event loop, runs tasks according to a cron expression, and requires no external dependencies. The problem is that it is completely in-memory: if the process restarts, any jobs that were scheduled to run during the downtime are silently skipped. There is no persistence, no retry logic, and no visibility into past or pending executions. For simple tasks where occasionally missing a run is acceptable, node-cron is perfectly adequate. For anything that must reliably fire payment processing, report generation, user notifications you need something more robust.
BullMQ solves the reliability problem by persisting jobs in Redis. Every scheduled job is stored before it runs, which means process restarts, crashes, and deployments do not cause silent job losses. BullMQ supports cron expressions through its repeat option, handles automatic retries with configurable backoff, and provides a real-time dashboard through Bull Board for monitoring job status. The trade-off is that it requires a running Redis instance. For applications that already use Redis for caching or session management, this is no additional overhead. Our deep-dive on Redis architecture in Node.js covers the setup patterns that apply directly to a BullMQ deployment.
Bree is a newer option that uses Node.js Worker Threads to run each job in an isolated thread rather than the main event loop. This prevents a slow or crashing job from affecting your application's main process. It supports cron syntax, has a clean TypeScript-first API, and is a good middle ground between node-cron's simplicity and BullMQ's full infrastructure requirement.
The Most Common Cron Expression Mistakes
Years of production debugging produce a consistent list of cron mistakes that developers make repeatedly. Knowing them in advance saves significant on-call time.
Using 12-hour time in the hour field: Cron uses 24-hour time exclusively. Writing
0 9 * * *means 9 AM. Writing0 9 PM * * *is invalid syntax. For 9 PM you write0 21 * * *. This mistake silently deploys without error and the job runs at the wrong time or not at all.Confusing
*/5with5in the minute field:5 * * * *runs once per hour at the 5-minute mark: 1:05, 2:05, 3:05.*/5 * * * *runs every five minutes: 1:00, 1:05, 1:10, 1:15. These produce completely different schedules and the confusion is extremely common.Forgetting timezone offset: If your cron runner uses UTC and your users are in New York, a job scheduled for
0 0 * * *fires at 8 PM Eastern in summer and 7 PM in winter. Always document your cron expressions with explicit timezone notes alongside the schedule.Using node-cron on a serverless platform: Serverless functions are stateless and short-lived. Registering a node-cron job inside an API Route Handler or Lambda function does not persist across invocations. The job definition is created, runs once during that request, and disappears. This produces no error but the job never fires again on schedule.
Setting day-of-month AND day-of-week simultaneously: Standard cron uses OR logic when both fields are specified.
0 0 1 * 1fires on the first of the month AND on every Monday not only on Mondays that fall on the first. Most developers expect AND behavior and get OR.
Cron Expression Quick Reference
Keep this table as a reference. The five fields in order, their valid value ranges, and the special characters each field supports:
Field 1 - Minute: 0–59, supports
*,-/Field 2 - Hour: 0–23, supports
*,-/Field 3 - Day of Month: 1–31, supports
*,-/Field 4 - Month: 1–12, supports
*,-/Field 5 - Day of Week: 0–7 (0 and 7 both = Sunday), supports
*,-/
Ready to build your next schedule without guessing? The tool also supports the extended six-field format used by some platforms that include a seconds field. For the architecture context around where cron jobs fit inside a larger Node.js system, our guide on Node.js performance, Worker Threads, and the event loop explains why job isolation matters for production reliability.
⚡ Build Your Cron Expression Free — Preview Next 5 Run Times Instantly
Frequently Asked Questions
What does * * * * * mean in a cron expression?
Five asterisks means the job runs every single minute, every hour, every day, every month, on every day of the week. This is the most permissive cron expression possible and is used almost exclusively for testing that a cron runner is active. In production it would execute your task 1,440 times per day. Always replace it with a specific schedule before deploying.
How do I run a cron job every 5 minutes?
Use the expression */5 * * * *. The */5 in the minute field means "every 5 minutes starting from minute 0": the job fires at :00, :05, :10, :15, :20, :25, :30, :35, :40, :45, :50, and :55 of every hour. On Vercel, this expression works directly in your vercel.json crons array. In node-cron you pass it as the first argument to cron.schedule().
What is the difference between node-cron and Vercel Cron Jobs?
node-cron is a Node.js library that schedules jobs inside a running process using the server's event loop. It requires a persistent server and loses all scheduled state if the process restarts. Vercel Cron Jobs are an HTTP-based scheduling system managed entirely by Vercel's infrastructure. Vercel sends a GET request to your specified Route Handler on your defined schedule, and your serverless function handles it. Vercel Cron Jobs work on serverless deployments where a persistent process does not exist, but they require your application to be deployed on Vercel's platform.
Why is my cron job running at the wrong time?
The most common cause is a timezone mismatch. Almost every cron system Unix cron, Vercel, AWS EventBridge, GitHub Actions uses UTC by default. If you expected the job to run at 9 AM in your local timezone and it runs at a different time, calculate the UTC offset for your timezone and adjust the hour field accordingly. In summer Eastern Time is UTC-4, so 9 AM Eastern is 0 13 * * * in UTC. In winter Eastern Time is UTC-5, so 9 AM Eastern becomes 0 14 * * *.
Can I use cron jobs in a serverless Next.js app?
Yes, but you cannot use node-cron or any in-process scheduler directly inside a Next.js Route Handler on a serverless platform. These libraries depend on a persistent process that serverless functions do not maintain. The correct approaches are: Vercel Cron Jobs if you deploy on Vercel, AWS EventBridge if you deploy on AWS Lambda, or an external queue like BullMQ running on a dedicated server that triggers your Next.js API endpoints via HTTP. All three approaches are reliable in production; the right choice depends on where your application is hosted and how complex your scheduling requirements are.
What is the cron expression for "every weekday at 9 AM"?
The expression 0 9 * * 1-5 runs your job at 9:00 AM from Monday through Friday. The 0 in the minute field means "at the top of the hour," 9 in the hour field specifies 9 AM in 24-hour UTC time, and 1-5 in the day-of-week field specifies the range from Monday (1) to Friday (5). Remember that this fires at 9 AM UTC, so adjust the hour field if your intended time is in a different timezone.
Continue Reading
View All HubLevel Up Your Workflow
Free professional tools mentioned in this article
Regex Tester & Debugger
Test, debug, and validate Regular Expressions (Regex) instantly. A free, client-side Regex Tester for developers to build safe patterns with zero logs.
Pomodoro Focus Timer
Boost your productivity using the best aesthetic Pomodoro timer online app. A free, unblocked 50/10 focus timer for Mac and Windows with music integration.
HTML to JSX / TSX Converter
Instantly convert HTML code to React JSX or TSX components. Automatically handles className, style objects, SVGs, and self-closing tags with secure, in-browser processing.
Markdown to HTML Converter
Convert Markdown to clean HTML instantly with live preview. Supports GitHub Flavored Markdown, tables, code blocks, and task lists. Free and browser-based.




