/ blog / how-to-test-cron-expression
// guide

How to Test a Cron Expression Before Running It

Published March 21, 2026 · CronBuilder.dev

Deploying a broken cron schedule is a special kind of painful — the job either runs at the wrong time, or doesn't run at all, and you don't find out until something is noticeably missing. The good news: there are several fast, low-effort ways to validate a cron expression before it ever touches a server.

// 5 methods covered
  1. Use an online cron expression tester
  2. Dry-run with a throw-away crontab
  3. Use croniter (Python) to list next runs
  4. Unit-test with node-cron / cron-parser
  5. Use a monitoring ping to confirm it ran
// method 1 — fastest

Use an Online Cron Expression Tester

The quickest way to validate any expression is to paste it into an online tool that shows the next run times immediately. No install, no terminal, no risk.

CronBuilder.dev (this site) does exactly this — paste any 5-field or 6-field expression and see:

  1. A plain-English explanation of what the schedule means
  2. A field-by-field breakdown (which part means what)
  3. The next 10 scheduled run times in your timezone
  4. Immediate syntax validation — errors are highlighted

This catches the two most common mistakes before anything runs: wrong field order and off-by-one errors (e.g. using 24 for midnight instead of 0).

Paste your expression here to validate it instantly.

Open Cron Tester →
// method 2 — linux terminal

Dry-run with a Throw-away Crontab

If you want to confirm the actual cron daemon accepts the syntax, install a temporary crontab, verify, then remove it. This is safe — it doesn't run the job, it just registers the schedule.

# 1. Add a safe test cron — echo is harmless
echo "*/5 * * * * echo 'test'" | crontab -

# 2. Verify cron accepted it
crontab -l

# 3. Remove the test crontab
crontab -r

If crontab -l shows your expression correctly, the syntax is valid. If cron rejects it, it will print an error to stderr.

Warning: crontab -r removes the entire crontab, not just the test line. If you have other jobs configured, save your current crontab first: crontab -l > ~/crontab.bak

Test with a high-frequency interval for rapid feedback

If you want to actually watch the job fire, temporarily set the interval to every minute and observe:

# Replace your real schedule with * * * * * temporarily
* * * * * /path/to/script.sh >> /tmp/cron-test.log 2>&1

# Watch the log in real time
tail -f /tmp/cron-test.log

Wait one minute. If the log updates, your job is running. Restore your real schedule once confirmed.

Tip: Always redirect stdout and stderr to a log file during testing: >> /tmp/cron-test.log 2>&1. Cron swallows output silently by default, which is why debugging is hard. The 2>&1 captures errors too.

// method 3 — python

Use croniter (Python) to List Next Run Times

If you're working in Python, croniter is the fastest way to compute next runs programmatically — useful for testing in scripts, CI pipelines, or notebooks.

pip install croniter
from croniter import croniter
from datetime import datetime

expr = "0 9 * * 1-5"  # your expression here
base = datetime.now()
it = croniter(expr, base)

print(f"Next 10 runs for: {expr}\n")
for _ in range(10):
    print(it.get_next(datetime).strftime("%Y-%m-%d %H:%M %A"))

Output for 0 9 * * 1-5 (weekdays at 9am):

2026-03-23 09:00 Monday
2026-03-24 09:00 Tuesday
2026-03-25 09:00 Wednesday
2026-03-26 09:00 Thursday
2026-03-27 09:00 Friday
2026-03-30 09:00 Monday
...

You can also validate that a specific timestamp should have triggered using croniter.match():

from croniter import croniter

# Did this expression match at exactly 9am on Monday?
print(croniter.match("0 9 * * 1-5", datetime(2026, 3, 23, 9, 0)))  # True
print(croniter.match("0 9 * * 1-5", datetime(2026, 3, 22, 9, 0)))  # False (Sunday)

This is particularly powerful for writing unit tests for schedule logic.

// method 4 — javascript / node

Unit-test with cron-parser (Node.js)

In Node.js projects, cron-parser lets you iterate over next runs in tests. This is the approach to use when your cron expression lives in config and you want it covered by CI.

npm install cron-parser
const parser = require('cron-parser');

const expr = '0 9 * * 1-5';
const interval = parser.parseExpression(expr, {
  tz: 'America/New_York'
});

console.log('Next 5 runs:');
for (let i = 0; i < 5; i++) {
  console.log(interval.next().toDate());
}

For unit tests with Jest or Vitest:

import parser from 'cron-parser';
import { describe, it, expect } from 'vitest';

describe('report schedule', () => {
  it('should run on weekdays only', () => {
    const interval = parser.parseExpression('0 9 * * 1-5');
    const next = interval.next().toDate();
    const day = next.getDay(); // 0=Sun, 6=Sat
    expect(day).toBeGreaterThan(0);
    expect(day).toBeLessThan(6);
  });

  it('should run at 9am', () => {
    const interval = parser.parseExpression('0 9 * * 1-5');
    const next = interval.next().toDate();
    expect(next.getHours()).toBe(9);
    expect(next.getMinutes()).toBe(0);
  });
});

This approach integrates cron validation directly into your test suite so a misconfigured schedule breaks the build rather than silently misfiring in production.

// method 5 — production verification

Use a Monitoring Ping to Confirm It Actually Ran

Once the job is deployed, the safest ongoing test is to have it ping a monitoring URL each time it runs. If the ping doesn't arrive within the expected window, you get an alert. This is called a heartbeat check or dead man's switch.

# In your crontab, add a curl ping after your job succeeds
*/5 * * * * /path/to/script.sh && curl -fsS https://hc-ping.com/YOUR-UUID

The && means the ping only fires if your script exits with code 0 (success). If the script fails or the cron doesn't run, the monitoring service alerts you.

Free options: Healthchecks.io offers a generous free tier (20 checks). BetterStack and Cronitor both offer free tiers with alerts via email and Slack.

This is the only method that catches runtime failures (script errors, environment issues, server downtime) rather than just syntax problems. For any production job you care about, add a monitoring ping.

Summary: Which Method to Use

Validating syntax quickly: Use cronbuilder.dev — paste, see the explanation and next run times, done. Takes 10 seconds.

Confirming the cron daemon accepts it: Use the throw-away crontab dry-run. Safe, takes 30 seconds.

Scripting / automation / CI: Use croniter (Python) or cron-parser (Node.js) in your test suite.

Production confidence: Add a monitoring ping. It's the only method that tells you if the job actually ran in production, not just whether the syntax was valid.

See also: Cron job not running? 10 reasons why  ·  Cron expression cheat sheet  ·  GitHub Actions cron schedule guide  ·  Expression reference library