A cron expression is a compact way to describe when an automated task should run, but small differences in field order, time zones, and scheduler behavior can produce surprising results. This guide explains how to build, validate, document, and troubleshoot recurring schedules across Linux cron, CI pipelines, and cloud schedulers.
Overview
Classic Unix cron usually uses five time fields followed by the command:
minute hour day-of-month month day-of-week commandFor example:
30 2 * * * /path/to/backup.shThis schedule runs the command at 02:30 every day, subject to the host's configured time zone and the cron implementation's behavior.
| Field | Allowed values | Common notation |
|---|---|---|
| Minute | 0–59 | *, 15, */10 |
| Hour | 0–23 | 0, 9-17, */4 |
| Day of month | 1–31 | 1, 1,15, 1-5 |
| Month | 1–12, or names in some implementations | *, 1-3 |
| Day of week | 0–7, often Sunday as 0 or 7 | 1-5, MON-FRI |
Special symbols make schedules readable and reusable:
- Asterisk (
*): every permitted value. In the minute field, it means every minute. - Comma (
,): a list, such as1,15for the first and fifteenth day of the month. - Hyphen (
-): an inclusive range, such as9-17for hours during a workday. - Slash (
/): a step interval, such as*/15for every 15 units within that field.
Do not assume that a cron expression is portable simply because it has five fields. A Linux crontab, a CI scheduler, and a managed cloud scheduler may use different field counts, support different special characters, or require a separate time-zone setting. Always check the target platform's syntax and validate the complete schedule before deploying it.
For a practical tool-assisted workflow, use a cron expression generator to inspect upcoming run times, then test the command independently. A generator can help verify the schedule, but it cannot confirm that the command has the correct permissions, environment variables, working directory, or failure handling.
Checklist by scenario
Every few minutes or hours
- Write the desired interval in plain language first: “every 10 minutes” or “at the start of every fourth hour.”
- Translate the interval into the relevant field. For example,
*/10 * * * *means every 10 minutes in a five-field cron format. - Confirm whether the scheduler supports a step value and whether it interprets it from zero or from the beginning of a range.
- Check that the command is safe to run repeatedly. Repeated execution should not create duplicate records, overlapping jobs, or conflicting file writes.
- Decide what should happen if one run is still active when the next trigger occurs. A lock, queue, timeout, or concurrency limit may be needed.
Daily or weekly jobs
- Choose the exact local time and write the time zone beside the expression before converting it.
- For a daily task at 04:15, a typical five-field expression is
15 4 * * *. - For weekdays at 09:00, a common expression is
0 9 * * 1-5, but confirm the platform's numbering and whether names such asMON-FRIare accepted. - Test the command with the same user account that will run it. Cron often has a smaller
PATHand a different home directory than an interactive shell. - Send standard output and errors to a controlled log destination, or route them into the platform's supported logging system.
Monthly or date-based jobs
- Clarify whether “monthly” means a calendar date, such as the first day, or a relative rule, such as the last weekday.
- Remember that a simple day-of-month value does not automatically mean “last day.” A schedule for day 31 will not run in shorter months.
- Use a wrapper script when the business rule is more complex than the scheduler's supported syntax. The scheduler can run the script daily, while the script decides whether today meets the rule.
- Test month boundaries, leap years, and the first run after a deployment.
CI pipeline schedules
- Read the CI provider's schedule format instead of copying a server crontab without review.
- Confirm whether the expression uses five fields, six fields with seconds, or a provider-specific wrapper.
- Check which branch, workflow, project, or pipeline is selected by the schedule.
- Verify that scheduled runs have the required secrets, permissions, environment variables, and checkout behavior.
- Define what happens when a previous run is still in progress: queue it, cancel it, skip it, or allow parallel execution.
Cloud or managed schedulers
- Identify where the time zone is configured. It may be an explicit scheduler property, a project setting, or a fixed default.
- Check whether the target is an HTTP endpoint, queue, function, or command runner, and document the authentication method.
- Review retry, timeout, duplicate-delivery, and failed-invocation behavior.
- Determine whether the platform reports missed schedules after an outage or simply resumes with the next occurrence.
- Use a request or job identifier so that repeated delivery can be detected safely.
What to double-check
Field order and platform syntax
Start with the scheduler's documented field order. The expression 0 0 * * * is commonly interpreted as midnight daily in a five-field format, but an implementation with a seconds field may require another position. Some systems accept macros such as @daily; others do not. Treat macros as platform-specific shorthand, not universal cron syntax.
Day-of-month and day-of-week behavior
When both day-of-month and day-of-week contain restrictions, classic cron implementations may treat them as an inclusive match: the job can run when either condition matches. Other schedulers may use an AND rule or reject the combination. If both fields matter, verify the behavior with a schedule preview and platform documentation. When precision is important, use separate schedules or a wrapper script rather than relying on an undocumented interpretation.
Time zones and daylight-saving changes
Every scheduled job should have an explicitly documented time zone. “02:00” is incomplete without one. Around daylight-saving transitions, a local time may occur twice or not occur at all. A scheduler may skip, repeat, delay, or otherwise handle that occurrence according to its implementation. For jobs that must run at a fixed interval, consider a UTC-based schedule where appropriate. For business events tied to local time, retain the business time zone and define acceptable behavior for ambiguous or missing times.
Missed runs and recovery
Do not assume that a scheduler will replay every missed occurrence after a host outage, disabled workflow, or suspended service. Document whether missed executions are skipped, caught up, or retried. If the work is important, make the job idempotent and add a separate reconciliation step that checks for missing periods.
Command context
A valid expression can still produce a failed job. Use absolute paths where practical, set required environment variables explicitly, choose a working directory deliberately, and quote filenames and arguments. Test permissions, network access, credentials, and log destinations under the scheduled execution identity. If the task processes API payloads or data files, a validation workflow such as the API payload debugging guide can help isolate malformed inputs from scheduling problems.
Reusable troubleshooting template
Record these details for every production schedule:
- Owner: team and named operational contact.
- Purpose: what the job does and why it runs.
- Expression: the exact schedule and platform.
- Time zone: including daylight-saving expectations.
- Command or target: endpoint, script, function, or pipeline.
- Expected history: the next several run times and acceptable delay.
- Failure handling: retries, alerts, timeouts, and recovery steps.
- Concurrency rule: whether overlapping executions are allowed.
Common mistakes
- Reading five fields as six: Count the fields from left to right and label each one before editing.
- Using local time without naming the zone: Add the time zone to the job record and scheduler configuration.
- Assuming “every 30 minutes” means on the hour and half-hour:
*/30commonly does that in the minute field, but verify the implementation and preview actual times. - Scheduling day 31 for a monthly job: Use a supported end-of-month rule or run a frequent wrapper that checks the date.
- Ignoring output: A job with no visible logs is difficult to distinguish from a job that never ran.
- Making a non-idempotent job repeatable: Add deduplication, locks, or a run key before enabling retries.
- Copying Linux syntax into CI or cloud settings: Recheck field count, time zone, permissions, retry policy, and target selection.
- Validating only the expression: Test the command, its dependencies, and its expected side effects separately.
When to revisit
Review a cron schedule before seasonal planning cycles, daylight-saving transitions, major deployments, infrastructure migrations, and changes to business reporting periods. Revisit it whenever the command, owner, time zone, credentials, branch, API endpoint, or data-retention rule changes. A schedule that worked on one server may need adjustment when moved to a container, CI platform, or managed cloud service.
Use this short review routine:
- State the intended schedule in plain language.
- Confirm the platform, field order, and time zone.
- Preview upcoming runs, including a month boundary and a daylight-saving transition when relevant.
- Run the command manually under the scheduled identity.
- Check logs, permissions, retries, and overlapping-run behavior.
- Record the owner, expected history, and recovery procedure.
- Set a calendar reminder to review the schedule when the workflow or tool changes.
For related web-development workflows, pair schedule validation with clear data checks. A JSON formatter and validator can help inspect structured job inputs, while an API testing workflow can verify an endpoint before a scheduled integration is enabled.