Run Tasks Locally Without Container Overhead
Run tasks as local processes.
Run tasks locally with the Process runner
The following example shows a shell script configured with the Process task runner, which runs a command as a child process on the Kestra host:
id: process_task_runnernamespace: company.team
tasks: - id: shell type: io.kestra.plugin.scripts.shell.Commands taskRunner: type: io.kestra.plugin.core.runner.Process commands: - echo "Hello World!"The Process task runner has no additional configuration properties — only the type is required.
Script tasks default to the Docker task runner if no taskRunner is specified. Set taskRunner.type to io.kestra.plugin.core.runner.Process explicitly when you want local process execution.
Working directory and file handling
Before each execution, Kestra prepares a working directory on the worker host. The following variables give your script access to it:
| Variable | Type | Description |
|---|---|---|
{{workingDir}} | Template expression | Absolute path to the working directory |
WORKING_DIR | Environment variable | Same path, available to any subprocess |
{{outputDir}} | Template expression | Dedicated output directory (only when outputDirectoryEnabled is set on the task) |
OUTPUT_DIR | Environment variable | Same path as {{outputDir}} when available |
Input files declared with inputFiles and namespace files are copied into the working directory before the process starts. Output files declared with outputFiles must be written to the working directory to be captured by Kestra.
Because the Process runner sets the process working directory to Kestra’s working directory, relative paths work without needing the {{workingDir}} prefix in commands.
The following self-contained example writes a file and captures it as an output:
id: process_output_filenamespace: company.team
tasks: - id: shell type: io.kestra.plugin.scripts.shell.Commands outputFiles: - out.txt taskRunner: type: io.kestra.plugin.core.runner.Process commands: - echo "Hello from Process runner" > out.txtYou can also pass an input file into the task and capture a transformed result. The input file is placed in the working directory under the key name you specify in inputFiles:
id: process_input_output_filesnamespace: company.team
inputs: - id: file type: FILE
tasks: - id: shell type: io.kestra.plugin.scripts.shell.Commands inputFiles: data.txt: "{{inputs.file}}" outputFiles: - out.txt taskRunner: type: io.kestra.plugin.core.runner.Process commands: - cp data.txt out.txtInstalling dependencies with beforeCommands
Use beforeCommands to install dependencies before the main script runs. When running inside the Kestra Docker image (which manages its own Python environment), pass --break-system-packages to avoid conflicts:
id: python_with_depsnamespace: company.team
inputs: - id: url type: URI defaults: https://jsonplaceholder.typicode.com/todos/1
tasks: - id: transform type: io.kestra.plugin.scripts.python.Script taskRunner: type: io.kestra.plugin.core.runner.Process beforeCommands: - pip install kestra requests --break-system-packages script: | import requests from kestra import Kestra
url = "{{ inputs.url }}"
response = requests.get(url) print('Status Code:', response.status_code) Kestra.outputs(response.json())By default, Python is the only programming language installed in the Kestra Docker image. If you are running Kestra directly on a host machine, whatever is installed on that machine is available to the process. To use other languages, ensure their runtimes are installed in your environment before running Kestra.
Logs and exit codes
Both stdout and stderr are captured and streamed to Kestra’s task logs in real time. Any non-zero exit code causes the task to fail with a TaskException reporting the exit code.
Behavior on worker interruption
When the Kestra worker is stopped or interrupted:
- The running process and all its child processes are killed immediately.
- The task is marked as failed.
- When the worker restarts, Kestra re-queues the task execution from the beginning.
There is no process-level resume — the task restarts from scratch on the next attempt.
Considerations
- No isolation: Unlike the Docker task runner, the Process runner provides no container boundary. Subprocesses run with the same OS user and permissions as the Kestra worker JVM, inherit the worker’s full environment, and share host CPU, memory, and disk with other running tasks.
- Platform support: Works on Linux, macOS, and Windows.
- Dependencies: Any tool or library used by the script must already be installed on the worker host (or installed via
beforeCommands).
Benefits
The Process task runner is well suited when you need to:
- Access local files or hardware (e.g., GPUs, local databases)
- Reuse locally configured software libraries or virtual environments
- Avoid the overhead of container startup
Combining task runners with Worker Groups
You can combine the Process task runner with Worker Groups to run tasks on dedicated servers that have specific software libraries or configurations. This combination allows you to leverage the compute resources of your Worker Groups while running tasks as local processes, without the overhead of containerization.
The following example demonstrates how to combine the Process task runner with Worker Groups to fully leverage the GPU resources of a dedicated server:
id: python_on_gpunamespace: company.team
tasks: - id: gpu_intensive_ai_workload type: io.kestra.plugin.scripts.python.Commands namespaceFiles: enabled: true commands: - python main.py workerGroup: key: gpu taskRunner: type: io.kestra.plugin.core.runner.ProcessNote that Worker Groups are an Enterprise Edition feature. To try them out, please reach out.
Was this page helpful?