How do you use Tekton Results to pass data between Tasks?
Quick Answer
Tekton Results allow a Task to emit string values by writing to files under the /tekton/results directory, which downstream Tasks can consume as parameter values using the $(tasks.taskname.results.resultname) variable substitution syntax within a Pipeline.
Detailed Answer
Think of Tekton Results like sticky notes that workers leave on a shared bulletin board in a factory assembly line. Each worker completes their station, writes a note with critical information like a part number or quality measurement, and pins it to the board. The next worker downstream reads those notes before starting their own job. In Tekton, Results are the mechanism that lets one Task produce output data that subsequent Tasks can consume as input, enabling dynamic data flow across an otherwise statically defined Pipeline.
At the Task level, you declare Results in the spec.results section with a name and an optional description. During execution, the Task step writes a value to a file at the path /tekton/results/<result-name>. The Tekton controller reads this file after the step container completes and stores the value as part of the TaskRun status. The value must be a string and, importantly, is subject to a size limit. In Tekton Pipelines v0.44 and later, individual results can be up to 4096 bytes by default, though this limit is configurable via the feature-flags ConfigMap. For larger data, you should write to a workspace volume and pass a file path as the result instead of the data itself. Results are terminated at the exact byte boundary of the file content, so avoid trailing newlines unless they are intentional, as they become part of the stored value.
Within a Pipeline, you reference a Task result using the variable substitution syntax $(tasks.<task-name>.results.<result-name>). This creates an implicit ordering dependency: the consuming Task will not start until the producing Task has completed successfully. For example, in a payments-api pipeline, a build-image Task can emit the full image digest as a result, and the subsequent deploy Task consumes that digest to ensure it deploys the exact image that was just built, not a mutable tag that could have been overwritten. This pattern eliminates the race condition where a deploy step pulls a latest tag that points to a different build than the one just tested. The Pipeline can also emit its own results by mapping Task results to Pipeline-level results in spec.results, making them accessible to external systems querying the PipelineRun status.
In production microservice workflows, Results become the glue connecting stages of complex pipelines. Consider a pipeline for the order-processing-service that first runs a generate-version Task to compute the semantic version from git tags, producing a result called version. The next Task, build-and-push, consumes that version to tag the container image and emits a result called image-digest containing the SHA256 digest. A parallel security-scan Task consumes the image-digest to scan the exact image for vulnerabilities and emits a scan-status result of either pass or fail. The deploy Task uses a when expression to check if scan-status equals pass before proceeding with the deployment, consuming the image-digest result to update the Kubernetes Deployment manifest with the immutable digest reference. This chain of Results creates a verifiable audit trail where every artifact is traceable from source commit to running container.
A common gotcha is attempting to use Results for large data transfers like test reports, coverage files, or build logs. Results are designed for small metadata values such as image digests, version strings, commit SHAs, or status flags. Writing megabytes of data to /tekton/results will either be truncated or cause the TaskRun to fail with a result size exceeded error. For large artifacts, use a shared workspace backed by a PersistentVolumeClaim where one Task writes files and the next Task reads them from the same mounted volume. Another pitfall is forgetting that Results create implicit dependencies. If Task B references a result from Task A, Task B cannot run in parallel with Task A even if you intended them to be parallel. Always review the Pipeline execution graph after adding result references to verify that the parallelism and ordering match your expectations. Use tkn pipelinerun describe to inspect result values after execution for debugging.