Handle YAML Multiline Strings and External Files in Terraform
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.
With keep_original_source = false, the Terraform provider has no awareness of tasks or plugins and cannot know their default values. Most conversion logic runs on the Kestra server. If you see a diff that is always present (even just after apply), your Terraform flow definition likely has a minor difference from what the server returns. In that case, copy the source from the Kestra UI into your Terraform files to eliminate the diff.
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 = <<EOTid: my-flownamespace: company.teaminputs: - name: my-value type: STRING required: true
tasks: - id: t2 type: io.kestra.core.tasks.log.Log message: first {{task.id}} level: TRACEEOT}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-flownamespace: company.teaminputs: - name: my-value type: STRING required: true
tasks: - id: t2 type: io.kestra.core.tasks.log.Log message: first {{task.id}} level: TRACEEOTresource "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.
The indent must match your actual flow’s indentation. Terraform treats YAML as a plain string and has no awareness of its structure, so manage indentation yourself using the indent function.
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: trueAnd 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: trueInclude full YAML parts
You can also include a full YAML spec inside another one.
Create 2 YAML files:
id: t1type: io.kestra.core.tasks.log.Logmessage: first {{task.id}}level: TRACEid: t2type: io.kestra.core.tasks.log.Logmessage: second {{task.id}}level: TRACECreate the YAML file for the flow:
tasks: - ${indent(4, file("t1.yml"))} - ${indent(4, file("t2.yml"))}Was this page helpful?