Conditional Rule Execution with when#
This guide explains how to use the when field (WF-01) to skip rules based on configuration values.
Problem#
A single pipeline often needs to adapt to different inputs: WGS vs. WES sequencing modes, optional annotation steps, or analysis paths that depend on coverage thresholds. Without conditional syntax, you either ship multiple pipeline files or rely on shell-level if statements that obscure the workflow structure.
Solution: when expressions#
Add a when field to any rule. The expression is evaluated against your [config] section before the DAG is built. When when evaluates to false, the rule is removed from the DAG entirely — its outputs are not expected and downstream rules that depend on them are handled accordingly.
[[rules]]
name = "fastqc"
when = "config.run_qc"
input = ["raw/sample_R1.fq.gz"]
output = ["qc/sample_fastqc.html"]
shell = "fastqc {input[0]} -o qc/"
Expression Syntax#
Simple truthiness#
when = "config.run_qc" # true if run_qc is truthy (boolean true, non-zero, non-empty)
when = "!config.skip_step" # true if skip_step is falsy
Comparisons#
when = 'config.mode == "WGS"' # string equality
when = 'config.mode != "WES"' # string inequality
when = "config.min_coverage >= 20" # numeric (>=, >, <=, <)
when = "config.threads == 8" # numeric equality
Boolean equality#
File existence#
Logical operators#
when = "config.run_qc && config.min_coverage >= 20"
when = 'config.mode == "WGS" || config.mode == "WES"'
when = '(config.run_annotation && config.min_coverage >= 20) || config.force_annotate'
Practical Example#
[config]
sequencing_mode = "WGS"
run_qc = true
min_coverage = 35
target_bed = ""
[[rules]]
name = "align"
# No `when` — always runs
input = ["raw/sample_R1.fq.gz"]
output = ["aligned/sample.bam"]
shell = "bwa mem ref.fa {input[0]} > {output[0]}"
[[rules]]
name = "fastqc"
when = "config.run_qc"
input = ["raw/sample_R1.fq.gz"]
output = ["qc/fastqc.html"]
shell = "fastqc {input[0]} -o qc/"
[[rules]]
name = "wgs_coverage"
when = 'config.sequencing_mode == "WGS"'
input = ["aligned/sample.bam"]
output = ["qc/coverage.txt"]
shell = "mosdepth qc/sample aligned/sample.bam"
[[rules]]
name = "wes_coverage"
when = 'config.sequencing_mode == "WES" && config.target_bed != ""'
input = ["aligned/sample.bam"]
output = ["qc/coverage.txt"]
shell = "mosdepth --by {config.target_bed} qc/sample aligned/sample.bam"
[[rules]]
name = "annotate"
when = "config.run_qc && config.min_coverage >= 20"
input = ["variants/sample.vcf.gz"]
output = ["annotated/sample.vcf.gz"]
shell = "vep --input_file {input[0]} --output_file {output[0]}"
With sequencing_mode = "WGS" and run_qc = true and min_coverage = 35:
align— runsfastqc— runs (run_qcis true)wgs_coverage— runs (sequencing_mode == "WGS")wes_coverage— skipped (sequencing_mode != "WES")annotate— runs (run_qc && min_coverage >= 20)
Checking Which Rules Will Run#
Use oxo-flow dry-run to preview the effective DAG after condition evaluation:
Skipped rules are listed separately in the dry-run output.
Full Example#
See examples/conditional_workflow.oxoflow for a complete WGS/WES adaptive pipeline that demonstrates all when expression types.