Prefect IntervalSchedule Migration: From Legacy Schedules to Prefect 3

· 5 min read · Automation

Migrate from deprecated prefect.server.schemas.schedules IntervalSchedule to Prefect 3 scheduling patterns — with side-by-side code comparisons, common errors, and a step-by-step upgrade path.

Prefect IntervalSchedule Migration: From Legacy Schedules to Prefect 3

If you have landed here from an import error, you are not alone. from prefect.server.schemas.schedules import IntervalSchedule stopped working and nobody told you.

Prefect 3 changed how schedules work. The old prefect.server.schemas.schedules module is gone. The scheduling model moved from server-side schema objects to deployment-level configuration. The concepts are the same but the code is different.

This guide covers the complete migration path: what changed, why, and exactly how to update your code with working examples.

Who This Is For

  • Data engineers with Prefect 2 pipelines that broke after upgrading to Prefect 3
  • Developers getting ImportError: cannot import name 'IntervalSchedule' and needing a fix
  • Vibe coders setting up new Prefect workflows and finding outdated tutorials referencing old imports
  • Teams planning a Prefect 2 to 3 migration who need to understand what changed

Familiarity with Prefect basics (flows and tasks) is assumed. If you are new to Prefect, see Schedule and Orchestrate Workflows with Prefect first.

What Changed

The Core Change

AspectPrefect 2Prefect 3
Importfrom prefect.server.schemas.schedules import IntervalScheduleNo separate import needed
Schedule objectIntervalSchedule(interval=timedelta(hours=1)){"interval": 3600} (dict)
AttachmentDeployment.build_from_flow(..., schedule=schedule)flow.serve(schedules=[...]) or flow.deploy(schedules=[...])
Schedule typesIntervalSchedule, CronSchedule, RRuleScheduleAll expressed as dicts with interval, cron, or rrule key
Server dependencySchedule enforced by Prefect serverSchedule managed by deployment

The Common Error

When you upgrade Prefect and run existing code, you get:

ImportError: cannot import name 'IntervalSchedule' from 'prefect.server.schemas.schedules'

Or sometimes:

ModuleNotFoundError: No module named 'prefect.server.schemas.schedules'

This is not a bug. The module was intentionally removed. Here is how to fix it.

Step 1: Replace IntervalSchedule Imports

Before (Prefect 2)

from datetime import timedelta
from prefect import flow
from prefect.server.schemas.schedules import IntervalSchedule

@flow
def daily_pipeline():
    """Run the daily data pipeline."""
    print("Pipeline running")

# Create schedule
schedule = IntervalSchedule(interval=timedelta(hours=24))

# Deploy with schedule
daily_pipeline.serve(name="daily-pipeline", schedule=schedule)

After (Prefect 3)

from prefect import flow

@flow
def daily_pipeline():
    """Run the daily data pipeline."""
    print("Pipeline running")

# Deploy with inline schedule
daily_pipeline.serve(
    name="daily-pipeline",
    schedules=[
        {"interval": 86400}  # 24 hours in seconds
    ],
)

No import needed. The schedule is a plain dictionary.

Step 2: Migrate CronSchedule

Cron schedules follow the same pattern.

Before (Prefect 2)

from prefect.server.schemas.schedules import CronSchedule

schedule = CronSchedule(cron="0 8 * * *", timezone="Europe/London")
my_flow.serve(name="morning-job", schedule=schedule)

After (Prefect 3)

my_flow.serve(
    name="morning-job",
    schedules=[
        {"cron": "0 8 * * *", "timezone": "Europe/London"}
    ],
)

Cron Quick Reference

PatternMeaning
0 8 * * *Daily at 8am
0 */6 * * *Every 6 hours
0 8 * * 1-5Weekdays at 8am
0 0 1 * *First day of each month
*/15 * * * *Every 15 minutes

Step 3: Migrate RRuleSchedule

For complex recurrence rules, RRule schedules become dict-based too.

Before (Prefect 2)

from prefect.server.schemas.schedules import RRuleSchedule

schedule = RRuleSchedule(
    rrule="FREQ=WEEKLY;BYDAY=MO,WE,FR;BYHOUR=9;BYMINUTE=0",
    timezone="Europe/London",
)
my_flow.serve(name="mwf-job", schedule=schedule)

After (Prefect 3)

my_flow.serve(
    name="mwf-job",
    schedules=[
        {
            "rrule": "FREQ=WEEKLY;BYDAY=MO,WE,FR;BYHOUR=9;BYMINUTE=0",
            "timezone": "Europe/London",
        }
    ],
)

Step 4: Multiple Schedules on One Deployment

Prefect 3 supports multiple schedules per deployment — something that was awkward in Prefect 2.

@flow
def reporting_pipeline():
    """Generate reports on multiple schedules."""
    print("Report generated")

reporting_pipeline.serve(
    name="multi-schedule-reports",
    schedules=[
        {"cron": "0 8 * * 1-5", "timezone": "Europe/London"},   # Weekday morning
        {"cron": "0 18 * * 5", "timezone": "Europe/London"},     # Friday evening summary
        {"cron": "0 9 1 * *", "timezone": "Europe/London"},      # Monthly on the 1st
    ],
)

Step 5: Migrate Deployment Files

If you used deployment.yaml or prefect.yaml, the schedule syntax also changed.

Before (prefect.yaml — Prefect 2)

deployments:
  - name: daily-pipeline
    flow_name: daily_pipeline
    schedule:
      interval: 86400

After (prefect.yaml — Prefect 3)

deployments:
  - name: daily-pipeline
    entrypoint: pipeline.py:daily_pipeline
    schedules:
      - interval: 86400
      # Or cron:
      # - cron: "0 8 * * *"
      #   timezone: "Europe/London"

Note the key changes: schedule (singular) became schedules (plural, list), and flow_name became entrypoint.

Step 6: Automated Migration Script

If you have many files to update, this script finds and flags all legacy imports.

import os
import re

def find_legacy_schedules(directory: str) -> list[dict]:
    """Scan Python files for deprecated Prefect schedule imports."""
    legacy_patterns = [
        r"from\s+prefect\.server\.schemas\.schedules\s+import",
        r"IntervalSchedule\(",
        r"CronSchedule\(",
        r"RRuleSchedule\(",
    ]

    findings = []
    for root, dirs, files in os.walk(directory):
        dirs[:] = [d for d in dirs if d not in {"node_modules", ".venv", "__pycache__"}]
        for filename in files:
            if not filename.endswith(".py"):
                continue
            filepath = os.path.join(root, filename)
            with open(filepath) as f:
                lines = f.readlines()
            for i, line in enumerate(lines, 1):
                for pattern in legacy_patterns:
                    if re.search(pattern, line):
                        findings.append({
                            "file": filepath,
                            "line": i,
                            "content": line.strip(),
                            "pattern": pattern,
                        })

    print(f"Found {len(findings)} legacy schedule references")
    for f in findings:
        print(f"  {f['file']}:{f['line']}{f['content']}")
    return findings

# Usage
find_legacy_schedules("./src")

Migration Checklist

Prefect Schedule Migration Checklist
─────────────────────────────────────
✓ Remove all imports from prefect.server.schemas.schedules
✓ Replace IntervalSchedule(interval=timedelta(...)) with {"interval": seconds}
✓ Replace CronSchedule(cron="...") with {"cron": "..."}
✓ Replace RRuleSchedule(rrule="...") with {"rrule": "..."}
✓ Change schedule= to schedules=[] (singular to plural list)
✓ Update prefect.yaml: schedule → schedules (list)
✓ Update flow_name → entrypoint in YAML
✓ Test each deployment: prefect deployment run <name>
✓ Verify schedules in Prefect UI dashboard

What This Replaces

Prefect 2 PatternPrefect 3 Equivalent
from prefect.server.schemas.schedules import IntervalScheduleNo import needed
IntervalSchedule(interval=timedelta(hours=1)){"interval": 3600}
CronSchedule(cron="0 8 * * *"){"cron": "0 8 * * *"}
schedule=schedule_objectschedules=[{...}]
One schedule per deploymentMultiple schedules per deployment
Server-side schema validationDeployment-level configuration

Next Steps

For a complete introduction to Prefect workflow orchestration, see Schedule and Orchestrate Workflows with Prefect. For building reusable task patterns in Prefect, see Prefect Reusable Task Blocks for Workflows.

For managing the secrets used in your Prefect deployments, see Secure Python Automation: Managing Secrets and Keys. For CI/CD integration with your Prefect pipelines, see CI/CD Pipeline for Data Workflows.

Automation services include Prefect migration, workflow design, and pipeline orchestration.

Get in touch to discuss migrating your Prefect workflows.

prefect.server.schemas.schedules intervalschedule prefect intervalschedule migration prefect.server.schemas.schedules import intervalschedule prefect schedule migration prefect 3 scheduling prefect intervalschedule deprecated prefect cron schedule prefect flow schedule prefect deployment schedule prefect scheduling guide

Enjoyed this article?

Get notified when I publish new articles on automation, ecommerce, and data engineering.

Get in touch

Related Articles