Outputs
Use step outputs when one step needs to pass a validated value or a materialized file path to a later step.
The current validated reference form is:
${steps.<step_id>.outputs.<output_name>}For value outputs from command steps, the producer must have an id, declare each output name in outputs, and write the value to DAGU_OUTPUT_FILE. Built-in actions can provide their own output contract. For example, a human task derives outputs from its form properties and publishes the validated operator input without an authored outputs field or DAGU_OUTPUT_FILE, and a decision step publishes its answers the same way.
A build workflow can instead declare path on an output. The command writes the file to ${outputs.<name>}, and dependent steps receive its final absolute path through ${steps.<id>.outputs.<name>}. Path outputs are not written to DAGU_OUTPUT_FILE.
Basic Example
steps:
- id: get_version
run: |
printf 'version=%s\n' "$(cat VERSION)" >> "$DAGU_OUTPUT_FILE"
outputs:
- name: version
- id: build_image
depends: get_version
run: docker build -t "myapp:${steps.get_version.outputs.version}" .This is more explicit than a bare ${VERSION} reference:
get_versiondeclares that it publishesversionbuild_imagedeclares the dependency that makes the output available- Dagu can report a passive notice if the step id, output name, or dependency is wrong
Human-task outputs use the same ${steps.<step_id>.outputs.<output_name>} reference and dependency rules. See Human Tasks for the generated-output behavior.
Output File Format
For each step attempt, Dagu creates an output file and exposes its path as DAGU_OUTPUT_FILE.
Write single-line values as name=value:
steps:
- id: inspect_build
run: |
printf 'version=v1.2.3\n' >> "$DAGU_OUTPUT_FILE"
printf 'artifact_url=https://example.test/app.tgz\n' >> "$DAGU_OUTPUT_FILE"
outputs:
- name: version
- name: artifact_urlWrite multi-line values with a delimiter:
steps:
- id: summarize
run: |
{
printf 'report<<REPORT\n'
./generate-report --format markdown
printf '\nREPORT\n'
} >> "$DAGU_OUTPUT_FILE"
outputs:
- name: reportRules:
- Every declared output must be written exactly once.
- Written output names must be declared.
- Duplicate output names fail the step attempt.
- Failed, aborted, timed-out, skipped, and not-yet-completed steps publish no outputs.
JSON Outputs
Declare type: json when the output value must be valid JSON.
steps:
- id: inspect
run: |
cat >> "$DAGU_OUTPUT_FILE" <<'EOF'
metadata<<JSON
{"image":"api","tag":"v1.2.3"}
JSON
EOF
outputs:
- name: metadata
type: json
- id: print_metadata
depends: inspect
env:
- METADATA: ${steps.inspect.outputs.metadata}
run: printf '%s\n' "$METADATA"Step output references read top-level declared output names. Nested output paths such as ${steps.inspect.outputs.metadata.tag} are not part of the strict reference syntax.
The separate ${<step_id>.output.<path>} form reads into a step's captured JSON output and does accept a path, which is how a decision step exposes ${classify.output.answers.department.choice}. It resolves against captured output rather than a declared output name, so the two forms are not interchangeable.
The matching ${<step_id>.outputs<path>} form reads into the payload a step published on its outputs channel, which need not be an object. A parallel step publishes an array there, so ${fanout.outputs} is the whole array and ${fanout.outputs[0].NAME} is one entry's value. Array indexes are valid in both path forms.
Dependencies
A step output reference makes the consuming step depend on the producing step. An explicit depends entry is optional.
steps:
- id: build
run: |
printf 'image=registry.example.com/app:v1.2.3\n' >> "$DAGU_OUTPUT_FILE"
outputs:
- name: image
- id: deploy
run: ./deploy.sh "${steps.build.outputs.image}"deploy runs after build and the reference resolves. dagu validate reports the edge as inferred: build -> deploy (steps[1].run), the API lists it in the step's inferredDepends field, and the UI graph draws it with a dashed line.
Rules:
- Inferred dependencies are unioned with
depends. An emptydepends: []does not suppress them. - A reference inside a
foreachbody makes the owningforeachstep depend on the producer. - Lifecycle handlers under
handler_oncreate no dependency. Neither do escaped references such as\${steps.build.outputs.image}or references in atemplate.rendertemplate body. - Two steps that reference each other's outputs, or a reference to a later step in a
type: chainDAG, form a cycle and the DAG fails to load. - Inferred dependencies only order execution. Behavior that
dependsenables beyond ordering, such as chat history inheritance between LLM steps, still needs an explicitdependsentry.
Running One Step
dagu start --only deploy runs deploy without the steps before it; they are recorded as skipped. The outputs deploy reads then come from finished runs of the same DAG:
# Reuse the outputs a finished run recorded
dagu start --only deploy --outputs-from 20260925_101500 pipeline.yaml
# Take one step's outputs from its own run
dagu start --only deploy --outputs-from 20260925_101500 --output-from build=20260926_080000 pipeline.yaml--outputs-fromcarries the outputs of steps that succeeded in that run, and copies its work directory.--output-from <step>=<run-id>takes one skipped step's outputs from its own finished run, and wins over--outputs-fromfor that step. The step must have succeeded in that run and cannot also be named by--only. Repeat the flag for more steps. The run records the run each reused step came from.- Only a skipped step that a selected step depends on, directly or through other steps, carries outputs. Without a source,
${steps.build.outputs.image}stays unresolved, as for any output that was never published. - The
success,failure,abort,wait, andexithandlers run only when a selected step is a graph end step, one that no other step depends on.handler_on.initruns as usual. --output <step>.<name>=<value>is deprecated; use--output-from.
The REST API takes the same selection as steps, outputsFromRunId, and outputsFromRuns; see Start DAG and the start command.
Output Names
Output names must match:
^[A-Za-z][A-Za-z0-9_]*$Use names such as version, image_tag, artifact_url, or record_count.
Capturing Stdout
Dagu never reads stdout for declared outputs, so a step that writes to DAGU_OUTPUT_FILE can print progress and logs to stdout freely.
The string form output: NAME works differently. It captures the step's entire stdout, trims surrounding whitespace, and exposes the result to later steps as the environment variable NAME:
steps:
- id: get_version
run: |
echo "Checking the build..."
echo "v1.2.3"
output: VERSION
- id: tag_image
depends: get_version
run: |
printf 'tag=%s\n' "$VERSION"VERSION holds both lines, not just v1.2.3. Use output: NAME only for commands that print nothing but the value, such as git rev-parse HEAD. When the command also logs to stdout, declare outputs and write the value to DAGU_OUTPUT_FILE instead.
Path Outputs
Path-backed outputs are available only in type: build workflows:
type: build
working_dir: /srv/build
steps:
- id: compile
inputs:
- name: source
path: source.txt
outputs:
- name: artifact
path: artifact.bin
run: compiler "${inputs.source}" -o "${outputs.artifact}"path and type are mutually exclusive on one output declaration. An eligible reusable step declares exactly one output and that output is path-backed. See Build Workflows for dependency inference, staging, reuse, and eligibility rules.
Large Results
Do not use step outputs for large reports, logs, media files, or full datasets. Write those to an artifact instead and publish only the small path or summary that later steps need.
steps:
- id: report
run: ./generate-report --format markdown
stdout:
artifact: reports/report.mdSee Artifacts for run artifact storage.

