Skip to main content

Schedules

A schedule is when a job auto-fires. The whole framework speaks cron — a five-field expression that's been the default scheduler vocabulary for forty years. This page walks through the syntax, the timezone rule, the live preview the editor renders, and the Schedule view that shows upcoming fires across every job.

For the broader mental model (job → schedule → run), see Concepts.


Cron at a glance

A cron expression has five required fields plus an optional sixth for seconds:

┌──── minute (0-59)
│ ┌── hour (0-23)
│ │ ┌── day of month (1-31)
│ │ │ ┌── month (1-12)
│ │ │ │ ┌── day of week (0=Sunday, 6=Saturday)
│ │ │ │ │ ┌── second (optional, 0-59)
0 2 * * *

The most common patterns:

GoalCron
Every minute (use for a smoke test, not steady state).* * * * *
Every 5 minutes.*/5 * * * *
Every hour, on the hour.0 * * * *
Every hour at minute :15.15 * * * *
Every day at 02:00.0 2 * * *
Every day at 02:30.30 2 * * *
Every weekday (Mon-Fri) at 09:00.0 9 * * 1-5
Every Monday at 09:30.30 9 * * 1
The 1st of every month at midnight.0 0 1 * *
Every quarter (1st of Jan/Apr/Jul/Oct) at 03:00.0 3 1 1,4,7,10 *
Twice a day (08:00 and 20:00).0 8,20 * * *

The four operators

OperatorMeaningExample
*"every value in the range".* * * * * = every minute.
,List specific values.0 6,12,18 * * * = at 06:00, 12:00, 18:00.
-Range.0 9 * * 1-5 = weekdays at 09:00.
/Step.*/10 * * * * = every 10 minutes; 0 */2 * * * = every two hours on the hour.

You can combine them: 5,15,25,35,45,55 9-17 * * 1-5 = every 10 minutes between 09:00 and 17:00, weekdays only. (Equivalent and tidier: */10 9-17 * * 1-5.)


Day-of-month vs day-of-week

If both day-of-month and day-of-week are constrained, the cron fires when either matches — not both. This matches the traditional Unix cron behaviour and is the only quirk worth memorising.

CronWhen it fires
0 9 15 * *The 15th of every month at 09:00.
0 9 * * 1Every Monday at 09:00.
0 9 15 * 1The 15th of every month OR any Monday — at 09:00.

For "Monday the 15th only", you can't express it with cron alone — let the job fire on Mondays and skip in a first step:

# python step: only proceed on the 15th
from datetime import date
def main(**kwargs):
if date.today().day != 15:
return {"skipped": "not the 15th"}
# ... real work

Timezones

The cron is evaluated in the timezone you pick on the job, not the framework's host timezone. This matters when the host runs on UTC but the business operates in Paris (or Sydney, or Mumbai).

SettingWhen the job fires
0 2 * * *, timezone UTC02:00 UTC every day — 03:00 / 04:00 Paris depending on DST.
0 2 * * *, timezone Europe/Paris02:00 Paris every day — 00:00 / 01:00 UTC depending on DST.

Daylight Saving Time is handled correctly when an IANA name is used: the scheduler skips or duplicates the cron firing as the wall clock jumps. With a fixed offset (Etc/GMT+1) DST is ignored — the job fires at the same UTC moment year-round.

Picking a timezone

Use the IANA name for the operating region (Europe/Paris, America/New_York, Asia/Tokyo). Use UTC only for jobs where wall-clock time genuinely doesn't matter (an hourly cleanup, a smoke test).


The live preview

The Job editor renders the next three fire times under the cron input as you type. It re-renders on every keystroke, so a malformed expression shows immediately ("invalid cron").

CronPreview
0 2 * * * (timezone Paris, today is Wed 17:00 Paris)Thu 02:00 · Fri 02:00 · Sat 02:00
30 9 * * 1next Mon 09:30 · the following Mon 09:30 · etc.
*/5 * * * *in 4 minutes · in 9 minutes · in 14 minutes
0 25 * * *(invalid — hour 25)

When the preview reads something different than you expected, you caught a bug before saving the job.


The Schedule view

The Jobs page has a 📅 Schedule view button in the toolbar. It opens a calendar of every upcoming fire across every enabled job — useful when you have ten cron jobs and want to spot collisions.

Nomaflow · ScheduleUpcoming fires for the next 7 days across all enabled jobs.MON 2702:30 · nomajde-daily-sync06:00 · reporting-refresh09:00 · activity-log-1TUE 2802:30 · nomajde-daily-sync06:00 · reporting-refresh09:00 · activity-log-1WED 2902:30 · nomajde-daily-sync02:45 · nomasx1-security-106:00 · reporting-refresh⚠ two heavy jobs at 02:30/02:45 — collision riskTHU 3002:30 · nomajde-daily-sync06:00 · reporting-refresh09:00 · activity-log-1LEGENDETLReportingAuditCollision flagged

Each chip is a fire — click it to jump to the job's catalogue card. Chips are coloured by tag (the calendar uses the first tag the job carries). Hours where two heavy jobs would run at the same time are flagged with a warning — Nomaflow doesn't enforce serial execution, but the calendar helps you avoid overlap.


Patterns most installs settle on

WorkloadScheduleWhy
Nightly ETLs0 2 * * * to 0 4 * * *Off-peak. Stagger when you have several — e.g. ETL A at 02:00, ETL B at 02:30, ETL C at 03:00.
Hourly syncs15 * * * *Avoid 0 * * * * — every other piece of software in the building fires on the hour.
Weekly audits0 6 * * 1Monday morning so the report's fresh when humans arrive.
Monthly reports0 7 1 * *Early on the 1st, before the morning rush.
Continuous polling*/5 * * * *5 minutes is the floor for steady state — finer cadences hammer the framework.
Smoke tests* * * * *Only enable temporarily — leaves a lot of run rows in 24 hours.

Anti-patterns

Don'tBecause
Schedule every job at 0 0 * * * (midnight).Several heavy jobs starting at the same moment can saturate the framework. Stagger by 15-30 minutes.
Use * * * * * for steady state.A run-per-minute fills the history fast and rarely matches a real business need.
Set a schedule when the job is operator-driven.Leave it manual-only — the catalogue still shows it, ▶ Run still works, no surprise fires at 3 AM.
Mix day-of-month and day-of-week.Cron's OR semantics will surprise you. Pick one.
Hard-code DST offsets.Use the IANA timezone name; DST is handled.

Disabling a schedule temporarily

Two ways to pause a job's auto-fires without losing the config:

OptionEffect
Enable toggle off on the catalogue card.Schedule ignored. Manual ▶ Run still works. Reversible in one click.
Empty the cron in the editor.Schedule removed entirely. Manual ▶ Run still works. The "manual-only" state is permanent until you re-add a schedule.

For a maintenance window or a release freeze, the enable toggle is the right tool — minimal config churn, fully reversible.


What's next

  • Create a job — the full Job editor (the schedule input lives in its ② Schedule section).
  • Catalogue — the Jobs page, where the schedule chip and next-run hint are surfaced.
  • Administration — multi-replica setup, scheduler lock, restart behaviour.