Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
astronomer avatar

Migrating Airflow 2 To 3

  • 942 installs
  • 412 repo stars
  • Updated July 27, 2026
  • astronomer/agents

migrating-airflow-2-to-3 is a Claude Code skill that upgrades Apache Airflow 2.x DAGs, operators, hooks, and configuration to Airflow 3.x for developers modernizing data pipeline codebases.

About

migrating-airflow-2-to-3 is an Astronomer agent skill that guides safe migration of Apache Airflow 2.x projects to the Airflow 3.x series. It should load as the first step for any migration-related request involving upgrade paths, compatibility issues, or breaking changes in DAG code. The skill covers DAG files, operators, hooks, and configuration updates, and suggests running ruff check with the AIR rule selector after edits to catch Airflow-specific issues. Developers reach for migrating-airflow-2-to-3 when they detect Airflow 2.x patterns, plan a version upgrade, or need help resolving breaking changes while modernizing scheduled data workflows.

  • Automatically detects Airflow 2.x code patterns and offers to run the migration
  • Runs Ruff with the complete AIR rule set (AIR30, AIR301–AIR312) including --fix and --unsafe-fixes
  • Recommends the safe upgrade path: 2.11 → 3.0.11 or directly to 3.1
  • Loads as the first step for any migration, upgrade or compatibility request
  • Post-edit hook suggests running ruff check --preview --select AIR after every code change

Migrating Airflow 2 To 3 by the numbers

  • 942 all-time installs (skills.sh)
  • +16 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Ranked #185 of 1,453 DevOps & CI/CD skills by installs in the Skillselion catalog
  • Security screen: MEDIUM risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/astronomer/agents --skill migrating-airflow-2-to-3

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs942
repo stars412
Security audit3 / 3 scanners passed
Last updatedJuly 27, 2026
Repositoryastronomer/agents

How do you migrate Apache Airflow 2.x DAGs to 3.x?

Safely upgrade Apache Airflow 2.x DAGs, operators, hooks and configuration to the Airflow 3.x series.

Who is it for?

Data engineers maintaining Airflow 2.x pipelines who need a guided upgrade to Airflow 3.x breaking changes.

Skip if: Teams not running Apache Airflow or projects only needing generic Python linting without DAG migration scope.

When should I use this skill?

Airflow 3 migration, upgrade, compatibility issues, or breaking changes are mentioned, or Airflow 2.x code is detected.

What you get

Migrated DAG files, updated operators and hooks, revised Airflow 3.x configuration, and ruff AIR compatibility check results.

  • Migrated DAG files
  • Updated operator and hook code
  • Airflow 3.x configuration

Files

SKILL.mdMarkdownGitHub ↗

Airflow 2 to 3 Migration

This skill helps migrate Airflow 2.x DAG code to Airflow 3.x, focusing on code changes (imports, operators, hooks, context, API usage).

Important: Before migrating to Airflow 3, strongly recommend upgrading to Airflow 2.11 first, then to at least Airflow 3.0.11 (ideally directly to 3.1). Other upgrade paths would make rollbacks impossible. See: https://www.astronomer.io/docs/astro/airflow3/upgrade-af3#upgrade-your-airflow-2-deployment-to-airflow-3. Additionally, early 3.0 versions have many bugs - 3.1 provides a much better experience.

Migration at a Glance

1. Run Ruff's Airflow migration rules to auto-fix detectable issues (AIR30/AIR301/AIR302/AIR31/AIR311/AIR312).

  • ruff check --preview --select AIR --fix --unsafe-fixes .

2. Scan for remaining issues using the manual search checklist in reference/migration-checklist.md.

  • Focus on: direct metadata DB access, legacy imports, scheduling/context keys, XCom pickling, datasets-to-assets, REST API/auth, plugins, and file paths.
  • Hard behavior/config gotchas to explicitly review:
  • Cron scheduling semantics: consider AIRFLOW__SCHEDULER__CREATE_CRON_DATA_INTERVAL=True if you need Airflow 2-style cron data intervals.
  • .airflowignore syntax changed from regexp to glob; set AIRFLOW__CORE__DAG_IGNORE_FILE_SYNTAX=regexp if you must keep regexp behavior.
  • OAuth callback URLs add an /auth/ prefix (e.g. /auth/oauth-authorized/google).
  • Shared utility imports: Bare imports like import common from dags/common/ no longer work on Astro. Use fully qualified imports: import dags.common.

3. Plan changes per file and issue type:

  • Fix imports - update operators/hooks/providers - refactor metadata access to using the Airflow client instead of direct access - fix use of outdated context variables - fix scheduling logic.

4. Implement changes incrementally, re-running Ruff and code searches after each major change. 5. Explain changes to the user and caution them to test any updated logic such as refactored metadata, scheduling logic and use of the Airflow context.

---

Architecture & Metadata DB Access

Airflow 3 changes how components talk to the metadata database:

  • Workers no longer connect directly to the metadata DB.
  • Task code runs via the Task Execution API exposed by the API server.
  • The DAG processor runs as an independent process separate from the scheduler.
  • The Triggerer uses the task execution mechanism via an in-process API server.

Trigger implementation gotcha: If a trigger calls hooks synchronously inside the asyncio event loop, it may fail or block. Prefer calling hooks via sync_to_async(...) (or otherwise ensure hook calls are async-safe).

Key code impact: Task code can still import ORM sessions/models, but any attempt to use them to talk to the metadata DB will fail with:

RuntimeError: Direct database access via the ORM is not allowed in Airflow 3.x

Patterns to search for

When scanning DAGs, custom operators, and @task functions, look for:

  • Session helpers: provide_session, create_session, @provide_session
  • Sessions from settings: from airflow.settings import Session
  • Engine access: from airflow.settings import engine
  • ORM usage with models: session.query(DagModel)..., session.query(DagRun)...

Replacement: Airflow Python client

Preferred for rich metadata access patterns. Add to requirements.txt:

apache-airflow-client==<your-airflow-runtime-version>

Example usage:

import os
from airflow.sdk import BaseOperator
import airflow_client.client
from airflow_client.client.api.dag_api import DAGApi

_HOST = os.getenv("AIRFLOW__API__BASE_URL", "https://<your-org>.astronomer.run/<deployment>/")
_TOKEN = os.getenv("DEPLOYMENT_API_TOKEN")

class ListDagsOperator(BaseOperator):
    def execute(self, context):
        config = airflow_client.client.Configuration(host=_HOST, access_token=_TOKEN)
        with airflow_client.client.ApiClient(config) as api_client:
            dag_api = DAGApi(api_client)
            dags = dag_api.get_dags(limit=10)
            self.log.info("Found %d DAGs", len(dags.dags))

Replacement: Direct REST API calls

For simple cases, call the REST API directly using requests:

from airflow.sdk import task
import os
import requests

_HOST = os.getenv("AIRFLOW__API__BASE_URL", "https://<your-org>.astronomer.run/<deployment>/")
_TOKEN = os.getenv("DEPLOYMENT_API_TOKEN")

@task
def list_dags_via_api() -> None:
    response = requests.get(
        f"{_HOST}/api/v2/dags",
        headers={"Accept": "application/json", "Authorization": f"Bearer {_TOKEN}"},
        params={"limit": 10}
    )
    response.raise_for_status()
    print(response.json())

---

Ruff Airflow Migration Rules

Use Ruff's Airflow rules to detect and fix many breaking changes automatically.

  • AIR30 / AIR301 / AIR302: Removed code and imports in Airflow 3 - must be fixed.
  • AIR31 / AIR311 / AIR312: Deprecated code and imports - still work but will be removed in future versions; should be fixed.

Commands to run (via uv) against the project root:

# Auto-fix all detectable Airflow issues (safe + unsafe)
ruff check --preview --select AIR --fix --unsafe-fixes .

# Check remaining Airflow issues without fixing
ruff check --preview --select AIR .

---

Reference Files

For detailed code examples and migration patterns, see:

  • [reference/config-changes.md](reference/config-changes.md) - airflow.cfg section moves, renames, and removals
  • [reference/migration-patterns.md](reference/migration-patterns.md) - Code examples for imports, scheduling, XCom, Assets, DAG bundles, runtime behavior changes
  • [reference/removed-methods.md](reference/removed-methods.md) - Removed model methods with SDK/API migration paths
  • [reference/migration-checklist.md](reference/migration-checklist.md) - Search patterns and fixes for issues Ruff doesn't catch

---

Quick Reference Tables

Key Import Changes

Airflow 2.xAirflow 3
airflow.operators.dummy_operator.DummyOperatorairflow.providers.standard.operators.empty.EmptyOperator
airflow.operators.bash.BashOperatorairflow.providers.standard.operators.bash.BashOperator
airflow.operators.python.PythonOperatorairflow.providers.standard.operators.python.PythonOperator
airflow.decorators.dagairflow.sdk.dag
airflow.decorators.taskairflow.sdk.task
airflow.datasets.Datasetairflow.sdk.Asset

Context Key Changes

Removed KeyReplacement
execution_datecontext["dag_run"].logical_date
tomorrow_ds / yesterday_dsUse ds with date math: macros.ds_add(ds, 1) / macros.ds_add(ds, -1)
prev_ds / next_dsprev_start_date_success or timetable API
triggering_dataset_eventstriggering_asset_events
templates_dictcontext["params"]

Asset-triggered runs: logical_date may be None; use context["dag_run"].logical_date defensively.

Cannot trigger with future `logical_date`: Use logical_date=None and rely on run_id instead.

Cron note: for scheduled runs using cron, logical_date semantics differ under CronTriggerTimetable (aligning logical_date with run_after). If you need Airflow 2-style cron data intervals, consider AIRFLOW__SCHEDULER__CREATE_CRON_DATA_INTERVAL=True.

Default Behavior Changes

SettingAirflow 2 DefaultAirflow 3 Default
scheduletimedelta(days=1)None
catchupTrueFalse

Callback Behavior Changes

  • on_success_callback no longer runs on skip; use on_skipped_callback if needed.
  • @teardown with TriggerRule.ALWAYS not allowed; teardowns now execute even if DAG run terminated early.

---

Resources

---

Related Skills

  • testing-dags: For testing DAGs after migration
  • debugging-dags: For troubleshooting migration issues
  • deploying-airflow: For deploying migrated DAGs to production

Related skills

How it compares

Pick migrating-airflow-2-to-3 over generic Python refactor skills when the codebase contains Airflow DAGs, operators, or hooks requiring version-specific breaking-change handling.

FAQ

What does migrating-airflow-2-to-3 upgrade?

migrating-airflow-2-to-3 upgrades Apache Airflow 2.x DAG files, operators, hooks, and project configuration to the Airflow 3.x series while addressing documented breaking changes and compatibility issues.

What lint command does migrating-airflow-2-to-3 suggest?

migrating-airflow-2-to-3 suggests running ruff check --preview --select AIR on the codebase after edits to surface Airflow-specific migration and compatibility problems.

Is Migrating Airflow 2 To 3 safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

DevOps & CI/CDinframonitoring

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.