Skip to content
Cron Expression Generator

Airflow cron format

Airflow Cron Expression Generator

Build and check the cron string you pass to schedule in an Apache Airflow DAG. Airflow parses five-field cron with the croniter library, adds presets such as @quarterly, @once and @continuous, and accepts croniter extras like L and MON#1. The generator explains each schedule and lists the next trigger times as you type.

Cron expression translator and generator

Format
Valid

5 fields, as in crontab. Presets @daily, @quarterly, @once and @continuous work, and so do croniter's L, 15W, MON#1 and L5.

English

At 6:00 AM, Monday through Friday.

العربية

في تمام الساعة 6:00 ص، من الإثنين إلى الجمعة.

    Quick presets

    Visual cron generator

    Pick options for each field — the expression above updates instantly.

    Next 5 executions

    Local time:

      Cheat sheet

      *
      Any value
      ,
      List — 1,15,30
      -
      Range — 1-5
      /
      Step — */10
      ?
      No specific value (day fields)
      @daily
      Macro for 0 0 * * *
      L
      Last day of the month, or last weekday — L5
      W
      Nearest Monday–Friday — 15W
      #
      Nth weekday — 6#3
      22-2
      Range that wraps past the end — 10 PM to 2 AM

      Airflow cron format

      The schedule argument takes a five-field cron string, laid out like a crontab line:

      FieldAllowed valuesSpecial characters
      Minute0–59, - * /
      Hour0–23, - * /
      Day of month1–31, - * ? / L W
      Month1–12 or JAN–DEC, - * /
      Day of week0–7 or SUN–SAT (0 and 7 = Sunday), - * ? / L #

      Special characters

      SymbolMeaning
      @Presets: @hourly, @daily, @weekly, @monthly, @quarterly (0 0 1 */3 *) and @yearly. @once runs the DAG a single time, @continuous starts a new run as soon as the last one ends, and schedule=None leaves the DAG to manual or API triggers.
      LThe last day of the month in day-of-month: 0 0 L * *. In day-of-week croniter puts L first, so L5 is the last Friday of the month; the Quartz form 5L is rejected.
      #The nth weekday of the month: MON#1 is the first Monday and 5#3 the third Friday.
      WThe weekday nearest to a date: 15W. It takes a single day, not a list or a range.
      ?Same as *, allowed on its own in either day field.
      /Steps: */30 in the minute field runs at minutes 0 and 30, and 0 */4 * * * every four hours from midnight.

      Airflow cron examples

      Click an expression to load it into the generator above.

      ExpressionSchedule
      At 12:00 AM.
      At 6:00 AM.
      At 6:00 AM, Monday through Friday.
      Every 30 minutes.
      At 0 minutes past the hour, every 4 hours.
      At 12:00 AM, on day 1 of the month, only in January, April, July, and October.
      At 12:00 AM, on the last day of the month.
      At 9:00 AM, on the first Monday of the month.
      At 6:00 PM, on the last Friday of the month.
      At 9:00 AM, on day 1 of the month or on Monday.
      Once only: Airflow creates a single run and never schedules the DAG again.
      Continuously: a new run starts as soon as the previous one finishes.

      When does an Airflow cron schedule run?

      Use it in a DAG

      Pass the expression to schedule. The time zone of start_date decides when it fires:

      import pendulum
      from airflow.sdk import dag, task
      
      
      @dag(
          schedule="0 6 * * 1-5",
          start_date=pendulum.datetime(2026, 1, 1, tz="Asia/Riyadh"),
          catchup=False,
      )
      def weekday_report():
          @task
          def build_report():
              ...
      
          build_report()
      
      
      weekday_report()

      To fix when runs start, whatever the Airflow version or settings, pass a timetable instead of a string:

      from airflow.sdk import CronDataIntervalTimetable, CronTriggerTimetable
      
      # Starts at 06:00; the logical date is 06:00 (Airflow 3 default)
      schedule=CronTriggerTimetable("0 6 * * 1-5", timezone="Asia/Riyadh")
      
      # Each run covers the interval that just ended (Airflow 2 default)
      schedule=CronDataIntervalTimetable("0 6 * * 1-5", timezone="Asia/Riyadh")

      On Airflow 2, import dag and task from airflow.decorators, and the timetables from airflow.timetables.trigger and airflow.timetables.interval. schedule_interval, deprecated since Airflow 2.4, is gone in Airflow 3: use schedule.

      Frequently asked questions

      Why didn’t my Airflow DAG run at the scheduled time?

      With a data-interval timetable (the Airflow 2 default), a run starts when its interval ends: the @daily run for 1 March starts at midnight on 2 March. Also check that start_date is in the past, that the DAG is unpaused, and which time zone start_date uses.

      What is the difference between @once, @continuous and None?

      @once creates a single run and never schedules the DAG again. @continuous starts a new run as soon as the previous one finishes, and needs max_active_runs=1. schedule=None creates no runs at all, so the DAG runs only when you trigger it by hand or through the API.

      Does Airflow support L, W and # in cron expressions?

      Yes, because Airflow parses cron with croniter: 0 0 L * * is the last day of the month, 0 9 * * MON#1 the first Monday and 0 18 * * L5 the last Friday. Quartz forms such as 5L, LW and L-2 are rejected.

      Which time zone does an Airflow cron schedule use?

      The time zone of the DAG’s start_date. With pendulum.datetime(2026, 1, 1, tz="Asia/Riyadh"), 0 6 * * * runs at 06:00 Riyadh time. A naive start_date uses [core] default_timezone, which is UTC by default.

      Cron generators for other platforms

      Browse all cron expression examples →