Kestra is language agnostic — you can use any programming language inside your workflows.
Kestra works with any programming language, with some having dedicated plugins and libraries that make it easier to send outputs and metrics back to Kestra.
Dedicated Plugins
Kestra currently supports the following programming languages with dedicated plugins:
Each of these plugins provides two task types:
- Commands: Execute scripts using a command-line interface (ideal for longer, pre-written files).
- Script: Write your code directly in YAML (best for short inline scripts).
Script example
An example of an inline Python script:
id: myflow
namespace: company.team
tasks:
  - id: script
    type: io.kestra.plugin.scripts.python.Script
    beforeCommands:
      - pip install requests kestra
    script: |
      from kestra import Kestra
      import requests
      response = requests.get('https://google.com')
      print(response.status_code)
      Kestra.outputs({'status': response.status_code, 'text': response.text})
Commands example
An example using Shell commands, similar to a terminal session:
id: myflow
namespace: company.team
tasks:
  - id: commands
    type: io.kestra.plugin.scripts.shell.Commands
    outputFiles:
      - first.txt
      - second.txt
    commands:
      - echo "1" >> first.txt
      - echo "2" >> second.txt
Run any language using the Shell task
With the Commands task, you can execute arbitrary commands inside a Docker container. This means you can run any language, as long as:
- Its dependencies can be included in a Docker image.
- It can be executed from a Shell command.
For handling outputs and metrics, use the same ::{}:: syntax as the Shell task.
Read more in Shell outputs and metrics.
Rust
Here is an example flow that runs a Rust file inside of a container using a rust image:
id: rust
namespace: company.team
tasks:
  - id: rust
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: rust:latest
    namespaceFiles:
      enabled: true
    commands:
      - rustc hello_world.rs
      - ./hello_world
The Rust code is saved as a namespace file called hello_world.rs:
fn main() {
    println!("Hello, World!");
}
When executed, the print statement is displayed in the Kestra logs:

Check out the full guide which includes using outputs and metrics.
Java
You can build custom plugins in Java which enable you to add custom tasks to your workflows. If you're looking to execute something simpler, you can use the Shell task with a Docker container.
Here is an example flow that runs a Java file inside of a container using a eclipse-temurin image:
id: java
namespace: company.team
tasks:
  - id: java
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: eclipse-temurin:latest
    namespaceFiles:
      enabled: true
    commands:
      - javac HelloWorld.java
      - java HelloWorld
The Java code is saved as a namespace file called HelloWorld.java:
class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
When executed, the print statement is displayed in the Kestra logs:

C
Here is an example flow that runs a C file inside of a container using a gcc image:
id: c
namespace: company.team
tasks:
  - id: c
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: gcc:latest
    namespaceFiles:
      enabled: true
    commands:
      - gcc hello_world.c
      - ./a.out
The C code is saved as a namespace file called hello_world.c:
#include <stdio.h>
int main() {
   printf("Hello, World!");
   return 0;
}
When executed, the print statement is displayed in the Kestra logs:

C++
Here is an example flow that runs a C++ file inside of a container using a gcc image:
id: cplusplus
namespace: company.team
tasks:
  - id: cpp
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: gcc:latest
    namespaceFiles:
      enabled: true
    commands:
      - g++ hello_world.cpp
      - ./a.out
The C++ code is saved as a namespace file called hello_world.cpp:
#include <iostream>
int main() {
    std::cout << "Hello World!";
    return 0;
}
When executed, the print statement is displayed in the Kestra logs:

TypeScript
You can execute TypeScript using the NodeJS plugin. To do so, you need to install TypeScript and compile our code to JavaScript using tsc.
Once done, you can then execute with NodeJS. However, do note that the file is now a .js file.
id: typescript
namespace: company.team
tasks:
  - id: ts
    type: io.kestra.plugin.scripts.node.Commands
    namespaceFiles:
      enabled: true
    commands:
      - npm i -D typescript
      - npx tsc example.ts
      - node example.js
This example can be found in the Node.js docs. The file is saved as example.ts.
type User = {
  name: string;
  age: number;
};
function isAdult(user: User): boolean {
  return user.age >= 18;
}
const justine: User = {
  name: 'Justine',
  age: 23,
};
const isJustineAnAdult: boolean = isAdult(justine);
console.log(isJustineAnAdult)
When executed, the print statement is displayed in the Kestra logs:

For more information, you can read more about Node.js with TypeScript on their official site.
PHP
Here is an example flow that runs a PHP file inside of a container using a php image:
id: php
namespace: company.team
tasks:
  - id: php
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: php:8.4-rc-alpine
    namespaceFiles:
      enabled: true
    commands:
      - php hello_world.php
The PHP code is saved as a namespace file called hello_world.php:
<?php
echo "Hello, World!";
?>
When executed, the print statement is displayed in the Kestra logs:

As of Kestra version 0.24, there is a dedicated PHP plugin. An example flow might look like the following using a script task:
id: php_script
namespace: company.team
tasks:
  - id: script
    type: io.kestra.plugin.scripts.php.Script
    script: |
      #!/usr/bin/php
      <?php
      echo "Hello, World!\\n";
      ?>
Check out the following example for the commands task:
id: php_commands
namespace: company.team
tasks:
  - id: commands
    type: io.kestra.plugin.scripts.php.Commands
    inputFiles:
      main.php: |
        #!/usr/bin/php
        <?php
        echo "Hello, World!\\n";
        ?>
    commands:
      - php main.php
Scala
Here is an example flow that runs a Scala file inside of a container using a sbtscala/scala-sbt image:
id: scala
namespace: company.team
tasks:
  - id: scala
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: sbtscala/scala-sbt:eclipse-temurin-17.0.4_1.7.1_3.2.0
    namespaceFiles:
      enabled: true
    commands:
      - scalac HelloWorld.scala
      - scala HelloWorld
The Scala code is saved as a namespace file called HelloWorld.scala:
object HelloWorld {
    def main(args: Array[String]) = {
        println("Hello, World!")
    }
}
When executed, the print statement is displayed in the Kestra logs:

Perl
Here is an example flow that runs a Perl file inside of a container using a perl image:
id: perl
namespace: company.team
tasks:
  - id: perl
    type: io.kestra.plugin.scripts.shell.Commands
    taskRunner:
      type: io.kestra.plugin.scripts.runner.docker.Docker
    containerImage: perl:5.41.2
    namespaceFiles:
      enabled: true
    commands:
      - perl hello_world.pl
The Perl code is saved as a namespace file called hello_world.pl:
#!/usr/bin/perl
use warnings;
print("Hello, World!\n");
When executed, the print statement is displayed in the Kestra logs:

As of Kestra version 0.24, there is a dedicated Perl plugin. An example flow might look like the following using a script task:
id: perl_inline
namespace: company.team
tasks:
  - id: perl_script
    type: io.kestra.plugin.scripts.perl.Script
    script: |
      my $message = "Hello from an inline Perl script!";
      print $message . "\\n";
Check out the following example for the commands task:
id: perl_commands
namespace: company.team
tasks:
  - id: perl
    type: io.kestra.plugin.scripts.perl.Commands
    commands:
      - perl -e 'print "Hello from Kestra!
Run any language using a custom Docker image
You can pre-install any language using a custom Docker image and use the Process Task Runner to execute it. Example using Go:
FROM kestra/kestra:latest
USER root
# Install Go
RUN apt-get update -y && apt-get install -y wget && \
    wget -qO- https://go.dev/dl/go1.24.3.linux-amd64.tar.gz | tar -C /usr/local -xzf - && \
    echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/golang.sh
# Set Go environment variables for Docker
ENV PATH="/usr/local/go/bin:${PATH}"
Then, point to that Dockerfile in your docker-compose.yml file:
services:
  kestra:
    build:
      context: .
      dockerfile: Dockerfile
    image: kestra-go:latest
Once you start Kestra using docker compose up -d, you can create a flow that directly runs Go tasks with your custom dependencies using the io.kestra.plugin.core.runner.Process task runner:
id: golang_process
namespace: company.team
tasks:
  - id: go_custom_dependencies
    type: io.kestra.plugin.scripts.go.Script
    taskRunner:
      type: io.kestra.plugin.core.runner.Process
    beforeCommands:
      - go mod init go_script
      - go get github.com/go-gota/gota/dataframe
      - go mod tidy
    script: |
      package main
      import (
          "os"
          "github.com/go-gota/gota/dataframe"
          "github.com/go-gota/gota/series"
      )
      func main() {
          names := series.New([]string{"Alice", "Bob", "Charlie"}, series.String, "Name")
          ages := series.New([]int{25, 30, 35}, series.Int, "Age")
          df := dataframe.New(names, ages)
          file, _ := os.Create("output.csv")
          df.WriteCSV(file)
          defer file.Close()
      }
    outputFiles:
      - output.csv
Was this page helpful?
