Run Airflow tasks in other languages
Airflow 3 enables users to write SDKs allowing definition of Airflow tasks in languages other than Python. Experimental SDKs for Golang and Java are available as of the Task SDK 1.3 release.
Support for other languages:
- Makes it easier for users to migrate workflows from legacy tools written in languages other than Python to Airflow.
- Makes Airflow more accessible to developers who prefer to code in another language.
- Gives users access to features unique to a supported language.
Multilanguage support is currently experimental and under development. This guide is subject to change and will be expanded over time. If you want to contribute to support writing Airflow tasks in the language of your choice, please reach out to the Airflow developers in the Airflow Slack or the Airflow Dev list.
Assumed knowledge
To get the most out of this guide, you should have existing knowledge of:
- Basic Airflow concepts. See Introduction to Apache Airflow.
- Depending on your target language:
- Basic Golang concepts. See Golang documentation.
- Basic Java concepts. See Learn Java.
How it works
Two environment variables configure which SDK coordinators are available, in addition to the default Python Task SDK:
AIRFLOW__SDK__COORDINATORS: a JSON containing all available coordinators.AIRFLOW__SDK__QUEUE_TO_COORDINATOR: a JSON that mapsqueuenames to coordinator names.
When adding tasks in other languages, you write the task logic in your target language in a separate module and if needed, compile it. Two elements need to be present: the dag_id, matching the id of the Dag in which the task is used, and a task_id that matches the id of the function decorated with @task.stub in the Dag. The Dag itself is written in Python.
When the task runs, Airflow uses the queue, dag_id, and task_id to find the matching function in the target language and executes it. How you declare the ids differs by language, as shown in the examples below.
Additionally, the SDKs contain a client for reading Variables, Connections, and XCom, as well as a logger. A value returned from the task becomes its XCom.
The compiled bundle and the coordinator configuration must be available on the Airflow component that runs your tasks.
When using task SDKs for other languages on Astro, you need to create matching worker queues in addition to setting AIRFLOW__SDK__COORDINATORS and AIRFLOW__SDK__QUEUE_TO_COORDINATOR as environment variables. For example, if you are using the Golang SDK, and set AIRFLOW__SDK__QUEUE_TO_COORDINATOR='{"golang": "go"}', you need to create a worker queue with the name golang.
Additionally, make sure any compiled binaries (e.g. Go executables) are compatible with linux/amd64, the architecture of workers on Astro Hosted.
Golang SDK example
The Golang SDK is experimental and still under development. You can track its status here.
Make sure your Airflow project is at least on version 3.3 and using the Task SDK version 1.3+.
Step 1: Configure the executable coordinator
Add two environment variables to your .env file. The first maps the golang queue to a coordinator named go. The second defines that coordinator, which scans the executables_root location for compiled bundles and runs them. The executables location needs to be accessible to your Airflow worker.
Step 2: Write a Go task bundle
-
Create the directory for the Go module, the parent directory of the
executables_root: -
Create a
go.modfile. Therequireline pins the SDK version, and thetooldirective makes the bundle packer available throughgo tool. Replace the placeholders with your versions. -
Create a
main.gofile with the task logic.The
RegisterDagsmethod binds Go functions to the Python Dag. Thedag_idyou pass toAddDagmust match the Python@dagid, and each function name passed toAddTaskmust match a Python stub task name. Thetransformfunction reads theextracttask’s XCom, sums the numbers, and pushes the result to XCom.
Step 3: Build the bundle
From the include/go_bundle directory, compile the bundle for the architecture of your Airflow containers (--goos linux for Linux containers). Use arm64 on Apple Silicon or amd64 on Intel and AMD machines. Note that you need Go 1.24 or later to compile the task bundle.
This writes a single executable to include/go_bundle/bin, which is the executables_root you set in Step 1.
Astro Hosted workers use linux/amd64, which means you’ll need to compile with --goos linux --goarch amd64 before deploying your project to Astro.
Step 4: Create the Dag
In your dags folder, create a file called go_task_syntax_example.py with the following code:
The Python extract task pushes a list of numbers to XCom, the Go transform task reads that list and sums it, and the Python load task reads the result back from Go.
The transform task uses @task.stub(queue="golang") and has no Python body. The stub tells Airflow the task’s name and its place in the Dag, and the queue value routes it to the Go coordinator. The dag_id and the stub task name must match the values registered in the Go bundle.
When using the Golang SDK on Astro, you need to create a matching worker queue in addition to setting AIRFLOW__SDK__COORDINATORS and AIRFLOW__SDK__QUEUE_TO_COORDINATOR as environment variables. For example, for AIRFLOW__SDK__QUEUE_TO_COORDINATOR='{"golang": "go"}', you need to create a worker queue with the name golang.
Java SDK example
The Java SDK is experimental and still under development. You can track its status in the java-sdk directory of the Airflow repository.
Make sure your Airflow project is at least on version 3.3 and using the Task SDK version 1.3+. The Java task runs as a compiled jar, so the Airflow component that runs your tasks also needs a Java runtime, for example openjdk-21-jre-headless. You’ll need to add the runtime to your packages.txt file to install it in your image.
Step 1: Configure the Java coordinator
Add two environment variables to your .env file. The first maps the java queue to a coordinator named java. The second defines that coordinator, which scans the jars_root location for compiled bundle jars and runs them.
Step 2: Write a Java task bundle
-
Create the module directory, including the
com/example/bundlepackage path where the source files live. You run Gradle from the module root, so change intoinclude/java_sdk: -
Create the Gradle project files.
gradle.propertiessets the SDK version in one place,settings.gradlenames the project and points Gradle at the Apache snapshot repository, andbuild.gradleapplies the Airflow SDK plugin, pulls in the SDK and its annotation processor, and pointsairflowBundleat the bundle’s main class. SetprojectVersionto the SDK version you are targeting; current builds are published as snapshots.gradle.properties:settings.gradle:build.gradle: -
Create the task class at
src/java/com/example/bundle/JavaEtlExample.java. The@Builder.Dagand@Builder.Taskannotations set the ids, and@Builder.XCom(task = "extract")adds the upstream Python task’s XCom as a method parameter. The returnedMapbecomes the task’s XCom. -
Create the bundle entry point at
src/java/com/example/bundle/EtlBundleBuilder.java. It implementsBundleBuilder, registers the Dag classes, and serves the bundle frommain.JavaEtlExampleBuilderis generated at compile time by the annotation processor from the@Builderannotations onJavaEtlExample.
Step 3: Build the bundle
From the include/java_sdk directory, build the bundle jar with Gradle, then copy the jar into the jars_root you set in Step 1. Building needs a JDK (this example builds with Java 21).
The coordinator loads the jar from include/java_bundle.
Step 4: Create the Dag
In your dags folder, create a file called java_task_syntax_example.py with the following code:
The transform task uses @task.stub(queue="java") and has no Python body. The queue value routes it to the Java coordinator, and the dag_id and stub task name must match the values registered in the Java bundle.
When using the Java SDK on Astro, you need to create a matching worker queue in addition to setting AIRFLOW__SDK__COORDINATORS and AIRFLOW__SDK__QUEUE_TO_COORDINATOR as environment variables. For example, for AIRFLOW__SDK__QUEUE_TO_COORDINATOR='{"java": "java"}', you need to create a worker queue with the name java.
Other ways to run tasks in other languages
You can also run tasks in other languages using the following methods:
- Use the BashOperator to run a script in another language. For example, you can use the BashOperator to run a JavaScript or R script. See Run a script in another programming language for more information.
- Use the KubernetesPodOperator to run any Docker image, which can include code in any language. See Use the KubernetesPodOperator to run a script in another language for more information.