How to Use Taskflow with XCom in Airflow: Simple Guide
Use the
@task decorator from Airflow's Taskflow API to define tasks that automatically push return values to XCom. Retrieve these values in downstream tasks by calling the upstream task function with .output inside the DAG context.Syntax
The Taskflow API uses the @task decorator to define tasks as Python functions. When a task function returns a value, Airflow automatically pushes it to XCom. To use this value in another task, call the upstream task function with .output as an argument.
Key parts:
@task: marks a Python function as an Airflow task.- Return value: automatically pushed to
XCom. .output: used to pull the XCom value from an upstream task.with DAG(...):context defines the workflow.
python
from airflow.decorators import dag, task from airflow.utils.dates import days_ago @dag(start_date=days_ago(1), schedule_interval='@daily', catchup=False) def example_dag(): @task def push_task(): return 'data from push_task' @task def pull_task(data): print(f'Received: {data}') data = push_task() pull_task(data) example_dag_instance = example_dag()
Example
This example shows two tasks: push_task returns a string that is automatically pushed to XCom. The pull_task receives this data as an argument and prints it. The DAG runs daily without catching up on past runs.
python
from airflow.decorators import dag, task from airflow.utils.dates import days_ago @dag(start_date=days_ago(1), schedule_interval='@daily', catchup=False) def taskflow_xcom_example(): @task def push_task(): return 'Hello from XCom' @task def pull_task(message): print(f'Received message: {message}') msg = push_task() pull_task(msg) dag = taskflow_xcom_example()
Output
Received message: Hello from XCom
Common Pitfalls
- Not using
@taskdecorator: Without it, return values won't be pushed to XCom automatically. - Trying to access XCom outside the DAG context: You must use the task function's
.outputinside the DAG definition. - Passing task instances instead of their outputs: Always pass
task_instance.output, not the task function itself. - Forgetting to set
catchup=Falseif you don't want backfill runs.
python
from airflow.decorators import dag, task from airflow.utils.dates import days_ago @dag(start_date=days_ago(1), schedule_interval='@daily', catchup=False) def wrong_xcom_usage(): def push_task(): # Missing @task decorator return 'data' @task def pull_task(data): print(f'Received: {data}') data = push_task() # This returns a string, but no XCom pushed pull_task(data) # pull_task receives the string directly # Correct way: @dag(start_date=days_ago(1), schedule_interval='@daily', catchup=False) def correct_xcom_usage(): @task def push_task(): return 'data' @task def pull_task(data): print(f'Received: {data}') data = push_task() pull_task(data)
Quick Reference
| Concept | Description |
|---|---|
| @task decorator | Defines a Python function as an Airflow task that supports XCom automatically. |
| Return value | Automatically pushed to XCom for downstream tasks. |
| .output | Used to access the XCom value from an upstream task. |
| DAG context | Tasks and their dependencies must be defined inside the DAG function. |
| catchup=False | Prevents running past scheduled DAG runs when starting fresh. |
Key Takeaways
Use @task decorator to enable automatic XCom push of return values.
Access upstream task data by passing task_function.output inside the DAG.
Always define tasks and dependencies inside the DAG context.
Avoid missing @task decorator to prevent silent XCom failures.
Set catchup=False to control backfill behavior when needed.