<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged kestra</title>
<link>https://coderlegion.com/tag/kestra</link>
<description>Powered by Question2Answer</description>
<item>
<title>Sibling Rivalry? How to Make Kestra Tasks Talk to Each Other</title>
<link>https://coderlegion.com/15665/sibling-rivalry-how-to-make-kestra-tasks-talk-to-each-other</link>
<description>&lt;p&gt;I'm putting together a video on sibling tasks in Kestra and thought I would build this idea out loud with you in a blog first.&lt;/p&gt;
&lt;p&gt;Let's jump in!&lt;/p&gt;
&lt;h3 id=&quot;what-are-sibling-tasks-&quot;&gt;What are sibling tasks?&lt;/h3&gt;
&lt;p&gt;Sibling tasks are tasks that have the same parent task. For the rest of this blog, we'll refer to sibling tasks within the context of a dynamic or looping construct.&lt;/p&gt;
&lt;p&gt;So in this case, we can be more specific and say sibling tasks are the tasks defined within the &lt;code&gt;tasks&lt;/code&gt; list of a loop. If we use &lt;code&gt;ForEach&lt;/code&gt; as an example, we could have something that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- id: my_loop
  type: io.kestra.plugin.core.flow.ForEach
  values: [&quot;alpha&quot;, &quot;beta&quot;]
  tasks:
    - id: first_sibling
      type: io.kestra.plugin.core.debug.Return
      format: &quot;Data for {{ taskrun.value }}&quot;

    - id: second_sibling
      type: io.kestra.plugin.core.log.Log
      # Accessing the sibling's output for the current iteration
      message: &quot;The first sibling said: {{ outputs.first_sibling[taskrun.value].value }}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ForEach&lt;/code&gt;, or &lt;code&gt;my_loop&lt;/code&gt;, is the parent, with the siblings being &lt;code&gt;first_sibling&lt;/code&gt; and &lt;code&gt;second_sibling&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;In this example you can see our log message contains info passed from &lt;code&gt;first_sibling&lt;/code&gt; with the expression syntax. You will see this in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://go.kestra.io/qTxlru&quot;&gt;docs&lt;/a&gt; as &quot;sibling task lookup&quot;. Pay attention to the differences between sequential and dynamic tasks, like looping. &lt;/p&gt;
&lt;h3 id=&quot;execution-amp-taskrun-context&quot;&gt;Execution &amp;amp; &lt;code&gt;TaskRun&lt;/code&gt; context&lt;/h3&gt;
&lt;p&gt;You may be familiar with the concept of context or scope and I think this is where things can start to get confusing.&lt;/p&gt;
&lt;p&gt;A task run is a single execution of an individual task within a larger workflow execution. When you are within a &lt;code&gt;ForEach&lt;/code&gt;'s task list, you'll want to use &lt;code&gt;taskrun.value&lt;/code&gt; to get the value associated with that run or iteration.&lt;/p&gt;
&lt;p&gt;This might be a bit different to how you've done looping with programming languages where you are scoped within the brackets of the loop. You don't need to think about iterations, just the work happening within the loop. &lt;/p&gt;
&lt;p&gt;Think of it like a &quot;You Are Here&quot; marker on a map. If you were hiking on a trail and came across a trail map with no marker to tell you where you are, it's not very helpful. You know you are on a trail and you could probably make a guess of where you are based on landmarks or time spent on the trail, but you could also be really wrong. And then get really lost.&lt;/p&gt;
&lt;p&gt;Bringing it back to programming and workflows, using a key to indicate what run or iteration becomes hugely important when you are running tasks concurrently. This means the context needs a hint at what iteration you are interested in. I know I'm looking for data in the loop, but which run? &lt;/p&gt;
&lt;h3 id=&quot;outputs&quot;&gt;Outputs&lt;/h3&gt;
&lt;p&gt;Outputs are how you pass data between tasks or flows. Standard tasks usually reference outputs via &lt;code&gt;{{ outputs.task_id.value }}&lt;/code&gt;. This gives you the value of a specific task's output.  &lt;/p&gt;
&lt;p&gt;In this case, we want to pass data between sibling tasks, which may look something like this &lt;code&gt;{{ outputs.first_sibling[taskrun.value].value }}&lt;/code&gt;. This gives you the values of a specific run or iteration from the &lt;code&gt;first_sibling&lt;/code&gt; task's output. This is very specific and helps prevent any conflict with concurrency or tasks firing in parallel.&lt;/p&gt;
&lt;p&gt;We can't assume &lt;code&gt;ForEach&lt;/code&gt; child tasks will run in parallel unless we set loop concurrency or use a parallel task.&lt;/p&gt;
&lt;p&gt;I highly recommend reading our &lt;a rel=&quot;nofollow&quot; href=&quot;https://go.kestra.io/gYXgq5&quot;&gt;best practices page&lt;/a&gt; on this topic.&lt;/p&gt;
&lt;h3 id=&quot;outputs-vs-execution-amp-taskrun-context&quot;&gt;Outputs vs. execution &amp;amp; TaskRun context&lt;/h3&gt;
&lt;p&gt;But let's say we want to access data outside of the loop. We can do that too, modifying our example from above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- id: my_loop
  type: io.kestra.plugin.core.flow.ForEach
  values: [&quot;alpha&quot;, &quot;beta&quot;]
  tasks:
    - id: first_sibling
      type: io.kestra.plugin.core.debug.Return
      format: &quot;Data for {{ taskrun.value }}&quot;

    - id: second_sibling
      type: io.kestra.plugin.core.log.Log
      # Accessing the sibling's output for the current iteration
      message: &quot;The first sibling said: {{ outputs.first_sibling[taskrun.value].value }}&quot;

- id: outside
  type: io.kestra.plugin.core.log.Log
  # Accessing the data for the `alpha` run specifically
  message: &quot;{{ outputs.first_sibling['alpha'].value }}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would give us the &quot;alpha&quot; iteration's output from the &lt;code&gt;first_sibling&lt;/code&gt; task as a value.&lt;/p&gt;
&lt;h3 id=&quot;where-it-gets-confusing&quot;&gt;Where it gets confusing&lt;/h3&gt;
&lt;p&gt;This tends to get confusing when you start using a mix of outputs and &lt;code&gt;taskRun&lt;/code&gt;. When your output exists outside of the loop, you use the standard syntax. Inside the loop? You need to give Kestra the key (or value) associated with the particular iteration. &lt;/p&gt;
&lt;p&gt;Additionally, your error messages can seem non-intuitive. You can will typically get an error where the value isn't found when you forget to use a key.&lt;/p&gt;
&lt;p&gt;So let's look again at this example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- id: outside
  type: io.kestra.plugin.core.log.Log
  message: &quot;{{ outputs.first_sibling['alpha'].value }}&quot; # correct
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if we ran this with the key, the value of the iteration we want to capture, we'll get an error.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- id: outside
  type: io.kestra.plugin.core.log.Log
  message: &quot;{{ outputs.first_sibling.value }}&quot; # will error
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;Unable to find `value` used in the expression `{{ outputs.first_sibling.value }}` at line 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;when-to-use-double-quotes&quot;&gt;When to use double quotes&lt;/h4&gt;
&lt;p&gt;Double quotes around your expressions give a clear indicator that this value is a string. Without them, you may get that unintuitive error that the value in the expression cannot be found.&lt;/p&gt;
&lt;p&gt;When I'm debugging my workflows, I usually try to make sure I have a key for my iteration and I've wrapped my expression in double quotes before I do any more extensive investigation. That usually solves it for me.&lt;/p&gt;
&lt;p&gt;This should show up as a linting warning with a nice yellow squiggle, but it depends on the task properties and types you are working with.&lt;/p&gt;
&lt;h4 id=&quot;when-to-use-foreach-and-foreachitem&quot;&gt;When to use &lt;code&gt;ForEach&lt;/code&gt; and &lt;code&gt;ForEachItem&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;A bigger topic is the differences between &lt;code&gt;ForEach&lt;/code&gt; and &lt;code&gt;ForEachItem&lt;/code&gt;, which we have a great &lt;a rel=&quot;nofollow&quot; href=&quot;https://go.kestra.io/GQ2cTW&quot;&gt;best practices page&lt;/a&gt; on.&lt;/p&gt;
&lt;p&gt;The TL;DR is use &lt;code&gt;ForEachItem&lt;/code&gt; when you want subflows and you are doing a lot of work on a lot of things. &lt;/p&gt;
&lt;p&gt;Let me know if in the comments if you want a blog or video (or both!) on this topic. &lt;/p&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;So that covers sibling tasks and outputs and expressions, oh my! Hopefully this adds a little more supplemental details to our docs on this topic. &lt;/p&gt;
&lt;p&gt;As always, let me know if there is something you want me to explain in a little more detail! I'll get a video related to this topic out next week too. &lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/15665/sibling-rivalry-how-to-make-kestra-tasks-talk-to-each-other</guid>
<pubDate>Thu, 23 Apr 2026 15:49:01 +0000</pubDate>
</item>
<item>
<title>Workflow Orchestration</title>
<link>https://coderlegion.com/10762/workflow-orchestration</link>
<description>&lt;p&gt;Just completed Module 2 of the Data Engineering Zoomcamp 2026. Built production-ready data pipelines using Kestra to process 26 million NYC taxi trip records.&lt;br&gt;
What I accomplished:&lt;/p&gt;
&lt;p&gt;Orchestrated ETL workflows with Kestra&lt;br&gt;
Ingested data from GitHub to GCS to BigQuery&lt;br&gt;
Implemented partitioned tables for query optimization&lt;br&gt;
Built MERGE operations for data deduplication&lt;br&gt;
Automated monthly data loads with schedule triggers&lt;br&gt;
Completed all homework questions (6/6)&lt;/p&gt;
&lt;p&gt;Key learnings:&lt;/p&gt;
&lt;p&gt;Template rendering with Pebble syntax&lt;br&gt;
Handling trigger.date for manual vs scheduled runs&lt;br&gt;
GCS storage class compatibility (REGIONAL vs STANDARD)&lt;br&gt;
IANA timezone format for DST handling&lt;br&gt;
BigQuery partitioning strategies&lt;/p&gt;
&lt;p&gt;Cost efficiency:&lt;br&gt;
Processed 2GB of data for less than one dollar, staying well within GCP's free tier.&lt;br&gt;
Check out my project on GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Derrick-Ryan-Giggs/module-2-workflow-orchestration&quot;&gt;https://github.com/Derrick-Ryan-Giggs/module-2-workflow-orchestration&lt;/a&gt;&lt;br&gt;
Thanks to DataTalksClub for this amazing free course.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10762/workflow-orchestration</guid>
<pubDate>Fri, 30 Jan 2026 08:37:43 +0000</pubDate>
</item>
</channel>
</rss>