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:
- Import patterns — Most reliable indicator
- API usage — Decorator styles, method signatures
- 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/@dagdecorators
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(notpython_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_upstreamwith 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:
- Multiple indicators: Most recent version wins
- No clear indicators: Default to 2.x patterns
- Mixed patterns: Note in conversion comments