Skip to main content
Flyte’s native scheduler lets you attach a schedule to any launch plan, so workflows run automatically without manual intervention. Flyte passes the exact scheduled kick-off time (not the wall-clock time of actual execution) to the workflow, ensuring deterministic, time-aware pipelines.
CronSchedule supports both standard cron expressions and AWS CloudWatch cron syntax (except @reboot). The older deprecated cron_expression field did not support AWS syntax.

Example workflow

The following workflow accepts a kickoff_time argument that Flyte populates automatically when a schedule fires:
import datetime
from flytekit import task, workflow

@task
def date_formatter(kickoff_time: datetime.datetime) -> str:
    return kickoff_time.strftime("%Y-%m-%d")

@workflow
def date_formatter_wf(kickoff_time: datetime.datetime) -> str:
    return date_formatter(kickoff_time=kickoff_time)

Cron schedules

A CronSchedule accepts a standard cron expression. An invalid expression causes the schedule to fail to register.
import datetime
from flytekit import CronSchedule, LaunchPlan

cron_lp = LaunchPlan.get_or_create(
    workflow=date_formatter_wf,
    name="date_formatter_cron_lp",
    schedule=CronSchedule(
        # Run at 09:00 UTC every day (standard cron expression)
        schedule="0 9 * * *",
        kickoff_time_input_arg="kickoff_time",
    ),
)
The kickoff_time_input_arg maps the schedule’s fire time to the kickoff_time parameter in the workflow. Omit it if your workflow does not need to know when it was triggered.

Common cron expressions

ExpressionMeaning
0 * * * *Every hour, on the hour
0 9 * * *Every day at 09:00 UTC
0 9 * * 1Every Monday at 09:00 UTC
0 0 1 * *First day of every month at midnight
*/15 * * * *Every 15 minutes
An incorrect cron expression will cause schedule registration to fail. Validate your expressions with a cron linter before deploying.

Fixed rate intervals

A FixedRate schedule fires at a constant interval — every N minutes, hours, or days.
import datetime
from flytekit import FixedRate, LaunchPlan
from datetime import timedelta

fixed_rate_lp = LaunchPlan.get_or_create(
    workflow=date_formatter_wf,
    name="date_formatter_fixed_rate_lp",
    schedule=FixedRate(
        duration=timedelta(minutes=10),
        # kickoff_time_input_arg can also be provided here
    ),
    fixed_inputs={"kickoff_time": datetime.datetime(2024, 1, 1)},
)
This launch plan fires every ten minutes. Like CronSchedule, FixedRate also accepts kickoff_time_input_arg if you want Flyte to inject the scheduled time into the workflow.
The Flyte native scheduler catches up on missed executions when the scheduler restarts. It records the last execution time in a snapshot every 30 seconds, so no scheduled runs are silently skipped after an outage.

Activating and deactivating schedules

After you register a launch plan with a schedule, you must explicitly activate it before executions begin.
1

Register your launch plan

Serialize and register your workflow and launch plan:
pyflyte register --project flyteexamples --domain development workflows/
2

Activate the schedule

Use flytectl to activate the specific versioned launch plan:
flytectl update launchplan \
  -p flyteexamples \
  -d development \
  date_formatter_cron_lp \
  --version <version> \
  --activate
3

Verify the schedule is active

List launch plans to confirm the active state:
flytectl get launchplan -p flyteexamples -d development

Deactivating a schedule

To stop a schedule from triggering new executions, archive the launch plan:
flytectl update launchplan \
  -p flyteexamples \
  -d development \
  date_formatter_cron_lp \
  --version <version> \
  --archive
Archiving a launch plan stops future scheduled executions. It does not cancel currently running executions.

How the native scheduler works

The Flyte native scheduler is built into flyteadmin and is backed by the gocron library. Key behaviors:
  • Snapshot-based recovery: The scheduler persists a snapshot of last-execution times to the database every 30 seconds. On restart, it reads this snapshot and catches up any missed scheduled executions before resuming normal operation.
  • Schedule updates: The scheduler polls the database every 30 seconds for changes to active schedules (activations and deactivations).
  • Rate limiting: A configurable rate limiter prevents the scheduler from flooding the admin API when catching up on many missed executions.
  • UTC timezone: You can configure the scheduler to use UTC for all schedule evaluations by setting useUTCTz: true in the workflow executor config.

Default inputs and fixed inputs

Launch plans support two kinds of pre-set values for workflow parameters:
from flytekit import LaunchPlan, FixedRate
from datetime import timedelta

# Fixed inputs cannot be overridden at execution time
# Default inputs can be overridden
batch_lp = LaunchPlan.get_or_create(
    workflow=date_formatter_wf,
    name="batch_nightly",
    schedule=FixedRate(duration=timedelta(hours=24)),
    fixed_inputs={"kickoff_time": datetime.datetime(2024, 1, 1)},
)
Use fixed_inputs for values that should never change regardless of who triggers the launch plan. Use default_inputs for values that are sensible defaults but can be overridden on manual runs.

Build docs developers (and LLMs) love