Working with YAML

Most Kestra resources must be described as YAML, such as kestra_flow and kestra_template.

Kestra uses full YAML in the Terraform definition because the resource structure is recursive and dynamic, so it cannot be described using Terraform’s internal schema.

There are 2 ways to handle YAML for a flow:

  • keep_original_source = true (default): the raw YAML is sent and saved in Kestra as-is.
  • keep_original_source = false: the YAML is encoded as JSON before being sent to the server, so comments and indentation are handled by the server.

These properties must be set at the provider level.

Terraform provides many functions for working with YAML content:

Simple multiline string example

Use a Heredoc String for a simple multiline string:

resource "kestra_flow" "example" {
namespace = "company.team"
flow_id = "my-flow"
content = <<EOT
id: my-flow
namespace: company.team
inputs:
- name: my-value
type: STRING
required: true
tasks:
- id: t2
type: io.kestra.core.tasks.log.Log
message: first {{task.id}}
level: TRACE
EOT
}

External files

A better approach is to use the file function. Create a .yml file alongside your .tf file and reference it in your resource:

id: my-flow
namespace: company.team
inputs:
- name: my-value
type: STRING
required: true
tasks:
- id: t2
type: io.kestra.core.tasks.log.Log
message: first {{task.id}}
level: TRACE
EOT
resource "kestra_flow" "example" {
namespace = "company.team"
flow_id = "my-flow"
content = file("my-flow.yml")
}

External files with template

For the most readable approach, use the templatefile function, which allows complex flows to include external files — which can themselves include other files.

Dealing with included YAML strings

For a flow that queries an external database, embedding the full query can produce a very long flow definition. Use templatefile to include an external file from the YAML instead.

Create a SQL file:

SELECT *
FROM ....

Create the YAML file for the flow:

tasks:
- id: query
type: io.kestra.plugin.jdbc.mysql.Query
url: jdbc:postgresql://127.0.0.1:56982/
username: postgres
password: pg_passwd
sql: |
${indent(6, file("my-query.sql"))}
fetchOne: true

And finally create the resource invoking the templatefile:

resource "kestra_flow" "example" {
namespace = "company.team"
flow_id = "my-flow"
content = templatefile("my-flow.yaml", {})
}

The .tf files reference the .yaml files, which reference the .sql files. The resulting flow will be:

tasks:
- id: query
type: io.kestra.plugin.jdbc.mysql.Query
url: jdbc:postgresql://127.0.0.1:56982/
username: postgres
password: pg_passwd
sql: |
SELECT *
FROM ....
fetchOne: true

Include full YAML parts

You can also include a full YAML spec inside another one.

Create 2 YAML files:

id: t1
type: io.kestra.core.tasks.log.Log
message: first {{task.id}}
level: TRACE
id: t2
type: io.kestra.core.tasks.log.Log
message: second {{task.id}}
level: TRACE

Create the YAML file for the flow:

tasks:
- ${indent(4, file("t1.yml"))}
- ${indent(4, file("t2.yml"))}

Was this page helpful?