Airflow Version Detection

When reading a DAG with read_dag, the LLM sees the raw source code and can identify the Airflow version from imports and patterns. This guide helps with version-appropriate conversion.

Detection Strategy

Version detection uses a combination of:

  1. Import patterns — Most reliable indicator
  2. API usage — Decorator styles, method signatures
  3. Feature presence — Datasets, Assets, TaskFlow

Version Indicators

Airflow 1.x

# 1.x-specific imports
from airflow.operators.python_operator import PythonOperator
from airflow.operators.bash_operator import BashOperator
from airflow.hooks.base_hook import BaseHook

# 1.x patterns
t1.set_downstream(t2)
t2.set_upstream(t1)

Signals:

  • airflow.operators.python_operator (renamed in 2.x)
  • airflow.operators.bash_operator (renamed in 2.x)
  • set_downstream() / set_upstream() methods
  • Missing @task / @dag decorators

Airflow 2.x

# 2.x imports
from airflow.operators.python import PythonOperator
from airflow.operators.bash import BashOperator
from airflow.decorators import dag, task
from airflow.datasets import Dataset

# 2.x patterns
@dag
def my_dag():
    @task
    def my_task():
        ...

Signals:

  • airflow.decorators — TaskFlow API (2.0+)
  • airflow.datasets — Dataset scheduling (2.4+)
  • from airflow.operators.python import (not python_operator)
  • >> / << dependency operators

Airflow 3.x

# 3.x imports
from airflow.assets import Asset
from airflow.sdk import DAG, task

# 3.x patterns
my_asset = Asset("s3://bucket/data")

@task(outlets=[my_asset])
def produce_data():
    ...

Signals:

  • airflow.assets — Asset API (replaces Dataset in 3.x)
  • airflow.sdk — New SDK module
  • Asset class with outlets/inlets

Feature Indicators

When reading a DAG, look for these features and use lookup_concept for each:

TaskFlow API

Detected when: @dag or @task decorators present

Lookup: lookup_concept("dag-to-flow") — maps directly to Prefect @flow / @task

Datasets (2.4+)

Detected when: from airflow.datasets import Dataset

Lookup: lookup_concept("dataset-to-automation") — convert to Prefect events or triggers

Dynamic Task Mapping

Detected when: .expand() method calls

Lookup: lookup_concept("dynamic-mapping") — convert to Prefect .map()

Version-Specific Guidance

From 1.x

  • Update all import paths
  • Replace set_downstream/set_upstream with function call ordering
  • XCom pull/push → return values and parameters
  • Consider using TaskFlow patterns for cleaner code

From 2.x

  • TaskFlow maps directly to Prefect @flow/@task
  • Datasets → Events or triggers
  • Connections → Blocks
  • Pools → Concurrency limits

From 3.x

  • Assets → Event-based automation
  • SDK patterns → Native Prefect patterns
  • Execution context → Run context

Handling Ambiguity

When version cannot be determined:

  1. Multiple indicators: Most recent version wins
  2. No clear indicators: Default to 2.x patterns
  3. Mixed patterns: Note in conversion comments