agentsclimarketplace

Bio workflow management nextflow pipelines skills nextflow pipelines

Skill bg-szy/TOP-SKILLS/skills/awesome-skills/bio-workflow-management-nextflow-pipelines__skills-nextflow-pipelines

Authors reproducible Nextflow DSL2 pipelines built on reactive dataflow, where processes communicate only through channels and execution order is not guaranteed. Use when deciding channel/dataflow (Nextflow) vs rule-based (Snakemake) authoring; wiring queue vs value channels and fixing shared-reference exhaustion with .first(); composing DSL2 modules and subworkflows with take/main/emit; selecting container/conda profiles and pinning images by digest for portability across local/SLURM/LSF/AWS Batch/Google Batch/Kubernetes executors; diagnosing why -resume misses the cache (nondeterministic input order, mtime on network filesystems, mutable :latest tags) with cache 'lenient' and -dump-hashes; managing work/ vs publishDir and dynamic retry escalation; and choosing whether to adopt an nf-core community pipeline or author from scratch.From its SKILL.md

Install
npx -y skills add bg-szy/TOP-SKILLS --skill bio-workflow-management-nextflow-pipelines__skills-nextflow-pipelines

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

17.2 KB, ~4.2k tokens by cl100k_base, as published. Nobody here has run it

Version Compatibility

Reference examples tested with: Nextflow 24.04+, fastp 0.23+, Salmon 1.10+, MultiQC 1.21+

Before using code patterns, verify installed versions match. If versions differ:

  • CLI: <tool> --version then <tool> --help to confirm flags

If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.

Note: Nextflow is DSL2-only (DSL1 was removed in 22.12) and calendar-versioned (24.x/25.x), so any single-script DSL1 tutorial is dead. The nf-validation plugin is deprecated in favor of nf-schema. A strict, statically-analyzable syntax (VS Code language server) is opt-in now and default in a later release; writing to it future-proofs a pipeline. Pin container images by immutable digest (@sha256:), never a moving tag such as :latest, or both reproducibility and -resume break.

Nextflow Pipelines

"Build a scalable, reproducible pipeline with Nextflow" -> Wire containerized processes together with asynchronous channels (reactive dataflow), so the engine fires each task as soon as its inputs are ready, caches completed tasks for -resume, and moves unchanged across executors by swapping a profile.

  • CLI: nextflow run main.nf -profile docker -resume
  • Groovy: DSL2 process / workflow / channel-operator syntax

The governing principle: Nextflow is reactive dataflow - processes talk ONLY through channels, execution order is NOT guaranteed

Nextflow is push-model dataflow: processes are pure functions wired together by asynchronous channels, every channel item is a future, and a process fires a task the instant a complete set of inputs is available on ALL its input channels. There is no target file, no backward DAG, no filename-to-rule matching. This is the opposite of Snakemake/CWL/WDL, which are pull/goal-oriented (name a target output, the engine walks a dependency DAG backward to decide what runs). Almost every downstream trap traces back to this one axis:

  • The model ENABLES truly dynamic pipelines: a process emits N files computed at runtime, the next process fans out over all N, with no DAG known in advance. Pull engines need a checkpoint/scatter escape hatch for this.
  • The COST is that "what will run" is not knowable by reading the script top-to-bottom. Independent branches interleave nondeterministically, so SAMPLE_A may finish after SAMPLE_Z. Never write logic that assumes order; carry an explicit sample key through the tuple instead.
  • "Why did only the first sample run?" and "why did -resume re-run everything?" are the two most common support questions, and both are direct symptoms of the dataflow model (see queue-vs-value channels and cache-miss diagnosis below).

A second principle sits above the engine: the DAG buys reproducibility of workflow LOGIC and nothing else automatically (Wratten et al. 2021 Nat Methods 18:1161-1168). A clean pipeline over unpinned tools is NOT reproducible. Pin the software environment (container by digest, conda by lockfile), the reference data and params, and control thread/locale/arch leaks (Grüning et al. 2018 Cell Syst 6:631-635). The engine gives one layer; the author pins the rest.

Decision: Nextflow vs the other engines

AxisNextflow (DSL2)SnakemakeWDL (Cromwell/miniwdl)CWL
Modelreactive dataflow (push, no target)pull/goal (target -> backward DAG)pull/goal (declared outputs)pull/goal (typed, declared)
Dynamic DAG (shape depends on runtime data)native, trivialcheckpoints (bolted on)scatter (static-ish)limited
Cloud/executor portabilitybest-in-class (swap by profile)good (v8 plugins, catching up)strong on GCP/Terravia Toil/Arvados
Community pipelinesnf-core (largest, curated)Workflow Catalog (smaller)WARP (Broad)limited
Best whencloud/production, dynamic pipelines, want nf-corePython shop, HPC, file-pattern logicTerra/AnVIL, GATK best practicesvendor-neutral portability, regulated

Honest take: Nextflow wins on executor portability, nf-core, and dynamic pipelines; Snakemake wins on approachability for Python users. Pick by the ecosystem to integrate with, not by benchmarks.

Decision: queue vs value channel (THE #1 footgun)

NeedChannel typeCreate withExhaustion behavior
One item consumed by one task (per-sample reads)queueChannel.of, .fromPath, .fromFilePairs, .splitCsvconsumed once, then empty forever
A shared value reused on EVERY task (a reference/index)value (singleton)Channel.value(x), .first(), .collect(), or a bare paramread unlimited times, never exhausted

The firing rule to memorize: a process launches a new task only when EVERY input channel can supply an item; when a queue input drains, no more tasks fire even if other inputs still have items. So a shared reference passed as a queue channel is consumed by the first sample and every later sample silently never runs (exit 0, no error). Corollary: if all of a process's inputs are value channels its outputs are value channels too; if any input is a queue channel the outputs are queue channels.

Decision: operator selection (and the silent-data-loss traps)

OperatorDoesTrap / when-wrong
maptransform each itempure only; no I/O side effects
collectALL items -> one list item (queue -> value)blocks until upstream closes; gathers inputs for one aggregating task (MultiQC)
groupTuplegroup by key into [key, [items]]bare form WAITS for the whole channel to close (serialization/deadlock); pass size: N or groupKey(key, n); SORT the grouped list or resume breaks
joininner-join two channels by keySILENTLY DROPS non-matching keys by default; use remainder: true or failOnMismatch: true
combineCartesian product (optional by:)intentional all-vs-all; distinct from join (1:1 merge)
mixinterleave channels into oneorder not preserved; pool outputs before a collect
branchroute items to named sub-channelsthe DSL2 idiom for conditional routing (single_end vs paired)
firstfirst item as a VALUE channelTHE queue -> value fix for shared references
ifEmptysupply a default if emptyguards the "empty branch silently vanishes" trap

Decision: executor (the portability payoff)

TargetexecutorBest whenWatch
Laptop/devlocaldevelopment, tiny data, -stub wiring testsone machine only
On-prem HPCslurm, lsf, sge, pbsshared cluster, on-prem datatune queueSize/submitRateLimit; scratch true on slow shared FS
Cloud batchawsbatch, google-batch, azurebatchelastic scale, no on-prem HPCinput localization copy dominates cost/time; Wave + Fusion cut it
Kubernetesk8salready running K8smore setup overhead

Never bake the executor into pipeline code; always set it in a profile so the same code moves across all of them.

Process and DSL2 modules (take / main / emit)

A DSL2 module wraps one tool as a process and can be included and called multiple times (aliased), which DSL1 could not. Subworkflows compose modules with named inputs/outputs.

// modules/fastqc.nf -- one tool, reusable, tested in isolation
process FASTQC {
    tag "${meta.id}"                                   // meta map threads sample identity through every operator
    container 'quay.io/biocontainers/fastqc:0.12.1--hdfd78af_0'  // pin an immutable tag/digest, never :latest
    label 'process_low'                                // maps to central resource config, decoupled from module code

    input:
    tuple val(meta), path(reads)                       // nf-core convention: [ meta, files ], meta = [id:'x', single_end:false]

    output:
    tuple val(meta), path('*.zip'), emit: zip          // meta round-trips so downstream always knows the sample

    script:
    """
    fastqc -t ${task.cpus} ${reads}
    """
}
// subworkflows/qc.nf -- take/main/emit names the interface
include { FASTQC } from '../modules/fastqc'
include { MULTIQC } from '../modules/multiqc'

workflow QC {
    take:
    reads

    main:
    FASTQC(reads)
    MULTIQC(FASTQC.out.zip.collect())                  // collect() gathers all samples' zips into ONE aggregating task

    emit:
    report = MULTIQC.out.report                        // access as QC.out.report from the caller
}

Channels: the shared-reference fix, explained

workflow {
    reads_ch = Channel.fromFilePairs(params.reads)     // queue: [id, [r1, r2]] per sample -- consumed once each
    index_ch = Channel.fromPath(params.index)          // queue: ONE item, the shared index

    // BUG if written ALIGN(reads_ch, index_ch): the index is consumed by sample 1,
    // its queue is then empty, and samples 2..N silently never fire (exit 0, no error).
    // .first() converts the queue to a VALUE channel, reusable on every task invocation.
    ALIGN(reads_ch, index_ch.first())
}

Resume: the task hash, and diagnosing a cache miss

-resume reuses a task only on an EXACT hit of the task hash, computed from the input file identities, the resolved script text, the container reference, and input values/params. A single-bit change in any component busts the cache and re-runs the task. The notorious silent causes:

  • Nondeterministic input ordering (collect/groupTuple/glob expansion) -> the ordered list is part of the hash. Fix: toSortedList() or .map{ k, v -> [k, v.sort()] }.
  • Mutable container tags (:latest, or a re-pushed version) -> pin by digest.
  • mtime hashing on network filesystems (Lustre/NFS) -> -resume works locally but misses on the cluster. Fix: cache 'lenient' (hashes size + path, ignores mtime).
  • Absolute paths, dates, $RANDOM, or hostname baked into the script string -> the script hash changes every run.
  • A deleted or moved work/ -> the hash hits the DB but the task dir is gone, forcing a re-run.
process ALIGN {
    // 'lenient' skips mtime -- the single most useful resume fix on HPC/cloud shared filesystems.
    // 'deep' hashes full file CONTENT (slower, robust when metadata lies); 'false' never caches.
    cache 'lenient'
    // ...
}

Definitive diagnosis: run both executions with -dump-hashes and diff which hash component differed, or nextflow log <run_name> -f hash,name,status,workdir to compare per-task hashes across runs. Everything else is guessing.

work/ is truth; publishDir is a side effect

Every task runs in an isolated work/<hash>/ dir holding the real outputs plus the forensic trail (.command.sh resolved script, .command.log, .exitcode). That directory IS the pipeline's output store and the ONLY thing -resume reads. publishDir merely copies or symlinks SELECTED outputs to a human-friendly location, and its failure can be SILENT because the task itself exited 0 in work/. Consequences:

  • mode: 'symlink' (default) breaks if work/ is later deleted; mode: 'copy' is safe to delete afterward; mode: 'move' breaks -resume (the output leaves work/), so use it only for terminal outputs.
  • Never rm -rf work/ if a resume might be wanted; use nextflow clean (which prunes the cache DB consistently). "Outputs missing but the pipeline succeeded" almost always means looking in publishDir instead of work/<hash>/.

Resources: dynamic retry escalation

process BIG {
    // 137=SIGKILL/OOM, 143=SIGTERM (SLURM wall-time kill); the 130..145 signal band + 104 (transient I/O) retry, fail fast otherwise.
    errorStrategy { task.exitStatus in ((130..145) + 104) ? 'retry' : 'terminate' }
    maxRetries 3
    memory { 8.GB * task.attempt }                     // task.attempt is 1-based; escalates 8 -> 16 -> 24 -> 32 GB
    time   { 4.h  * task.attempt }                     // a transient OOM auto-escalates instead of killing the run

    script:
    """
    memory_intensive_command
    """
}

errorStrategy values are 'terminate' (default), 'retry', 'ignore' (drop the failed task's outputs and continue over survivors), and 'finish' (graceful drain). The nf-core process.resourceLimits directive (Nextflow 24.04+, which replaced the pre-3.0 check_max pattern) clamps the escalated request to the machine/queue ceiling so 8.GB * task.attempt never asks for more than a node has.

Executors and profiles: portability

// nextflow.config -- executor lives in a profile, never in the pipeline code
profiles {
    docker      { docker.enabled = true }
    singularity { singularity.enabled = true }
    slurm {
        process.executor = 'slurm'
        executor { queueSize = 100; submitRateLimit = '10/1min' }   // avoid hammering the scheduler
    }
    awsbatch {
        process.executor = 'awsbatch'
        aws.region = 'us-east-1'
    }
}

process {
    cpus = 2; memory = '4 GB'; time = '1h'             // sane defaults
    withLabel: 'process_high' { cpus = 16; memory = '64 GB'; time = '12h' }  // labels centralize per-tier tuning
}

Run with -profile slurm,singularity (comma-separated, NO spaces; later profiles override earlier).

Adopt an nf-core pipeline before authoring

For any mainstream analysis (RNA-seq, variant calling, ATAC, methylation, amplicon), a curated nf-core/<pipeline> already encodes years of QC, containerized modules, nf-test regression tests, and institutional configs. Reinventing it is months of work and worse QC. Pin the revision: nextflow run nf-core/rnaseq -r 3.14.0 -profile test,docker --outdir results. DIY is justified only for genuinely novel logic. See workflow-management/nf-core-pipelines for running, configuring, and building samplesheets against community pipelines; this skill covers AUTHORING.

Common Errors

SymptomCauseFix
Only the first sample processed, exit 0, no errorshared reference on a queue channel, exhausted after task 1.first() / Channel.value on the reference
Pipeline hangs at a grouping stepgroupTuple with no size on a channel that never closessize: N or groupKey(key, n)
Some samples silently disappear mid-pipelinejoin dropped non-matching keysremainder: true or failOnMismatch: true
-resume re-runs everythingnondeterministic input order, or :latest tag, or mtime on network FSsort inputs; pin container digest; cache 'lenient'
Resume works locally, misses on the clustermtime unreliable on Lustre/NFScache 'lenient'
Outputs missing but the pipeline "succeeded"publishDir failed silently, or looked in publishDir not work/check work/<hash>/; use mode: 'copy'
Resume broken after cleanupdeleted work/never rm -rf work/; use nextflow clean
OOM kills a long run near the endfixed memory, no escalationmemory { 8.GB * task.attempt } + conditional retry
Wrong result, no error, after a base image updatemutable tag served a stale cache hitpin by digest; cache 'deep' for critical inputs
Huge cloud bill / slow S3 pipelineexplicit stage-in/out copies of large filesWave + Fusion (POSIX over object store)
-profile test docker ignores dockerspace instead of comma-profile test,docker

Related Skills

  • workflow-management/nf-core-pipelines - Run and configure community pipelines (the RUNNING counterpart to this authoring skill)
  • workflow-management/snakemake-workflows - Pull/goal-oriented alternative for Python shops and file-pattern logic
  • workflows/rnaseq-to-de - End-to-end RNA-seq quantification to differential expression
  • read-qc/quality-reports - QC steps a pipeline orchestrates (FastQC/MultiQC)

References

  • Di Tommaso P, Chatzou M, Floden EW, Prieto Barja P, Palumbo E, Notredame C. 2017. Nextflow enables reproducible computational workflows. Nat Biotechnol 35(4):316-319.
  • Ewels PA, Peltzer A, Fillinger S, Patel H, Alneberg J, Wilm A, Garcia MU, Di Tommaso P, Nahnsen S. 2020. The nf-core framework for community-curated bioinformatics pipelines. Nat Biotechnol 38(3):276-278.
  • Wratten L, Wilm A, Göke J. 2021. Reproducible, scalable, and shareable analysis pipelines with bioinformatics workflow managers. Nat Methods 18:1161-1168.
  • Grüning B, Chilton J, Köster J, et al. 2018. Practical computational reproducibility in the life sciences. Cell Syst 6(6):631-635.

What ships with it: 1 file

5.8 KB alongside SKILL.md

Keep looking

Skills are one crate of 326,871. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.