Nextflow — Scalable Scientific Workflow Engine
Overview
Nextflow implements a dataflow programming model where processes (containerized execution units) consume and emit data through channels (asynchronous queues). This design enables implicit parallelization — processes run as soon as their input channels have data, without manual dependency management. Nextflow handles process orchestration across local machines, HPC clusters (SLURM, SGE, PBS), and cloud platforms (AWS Batch, Google Cloud Life Sciences, Azure Batch) by swapping a single configuration profile. The nf-core community provides 100+ validated Nextflow pipelines (RNA-seq, WGS, ChIP-seq, scRNA-seq) following best practices with automated testing.
When to Use
- Building containerized bioinformatics pipelines that must run on HPC, AWS, and local environments without code changes
- Using nf-core community pipelines (nf-core/rnaseq, nf-core/sarek, nf-core/chipseq) out of the box
- Processing thousands of samples with implicit parallelization across a SLURM cluster
- Writing pipelines where each step runs inside a Docker or Singularity container for reproducibility
- Monitoring pipeline execution and resuming from checkpoints after failures with
-resume - Use Snakemake instead for Python-native rule-based workflows where Python integration is prioritized
- Use WDL/Cromwell instead for clinical genomics pipelines that require CWL/WDL standards compliance
Prerequisites
- Software: Java 11+, Nextflow (self-contained launcher)
- Containers: Docker or Singularity for process isolation (recommended)
- Optional: nf-core tools for community pipeline management
Check before installing: The tool may already be available in the current environment (e.g., inside apixi/condaenv). Runcommand -v nextflowfirst and skip the install commands below if it returns a path. When running inside a pixi project, invoke the tool viapixi run nextflowrather than barenextflow.
# Install Nextflow (self-contained JAR — no sudo required)
curl -s https://get.nextflow.io | bash
chmod +x nextflow
export PATH="$PWD:$PATH"
# Verify
nextflow -version
# Nextflow version 24.10.1
# Install nf-core tools (Python)
pip install nf-core
# Pull an nf-core pipeline
nextflow pull nf-core/rnaseq
Quick Start
// hello.nf — minimal Nextflow pipeline
nextflow.enable.dsl = 2
process GREET {
input: val name
output: stdout
script: "echo 'Hello, ${name}!'"
}
workflow {
Channel.of('World', 'Nextflow') | GREET | view
}
# Run the pipeline
nextflow run hello.nf
# Hello, World!
# Hello, Nextflow!
Core API
Module 1: Processes — Containerized Task Units
Define processes with inputs, outputs, and shell/script directives.
// process_example.nf
nextflow.enable.dsl = 2
process ALIGN_READS {
// Container for this process
container 'quay.io/biocontainers/star:2.7.11a--h0033a41_0'
// Resource directives
cpus 16
memory '32 GB'
// I/O declarations
input:
tuple val(sample_id), path(reads_r1), path(reads_r2)
path genome_index
output:
tuple val(sample_id), path("${sample_id}.Aligned.sortedByCoord.out.bam")
path "${sample_id}.Log.final.out", emit: log
// Shell command
script:
"""
STAR --runThreadN ${task.cpus} \\
--genomeDir ${genome_index} \\
--readFilesIn ${reads_r1} ${reads_r2} \\
--readFilesCommand zcat \\
--outSAMtype BAM SortedByCoordinate \\
--outFileNamePrefix ${sample_id}.
"""
}
Module 2: Channels — Data Queues Between Processes
Create and transform channels for flexible data routing.
nextflow.enable.dsl = 2
workflow {
// Value channel (broadcast)
genome_ch = Channel.value(file("GRCh38.fa"))
// List channel
samples_ch = Channel.of('ctrl_1', 'ctrl_2', 'treat_1', 'treat_2')
// File channel from glob pattern
reads_ch = Channel.fromFilePairs("data/*_{R1,R2}.fastq.gz")
// Emits: [sample_id, [R1_file, R2_file]]
// From a CSV sample sheet
sample_sheet = Channel.fromPath("samplesheet.csv")
.splitCsv(header: true)
.map { row -> tuple(row.sample, file(row.fastq_1), file(row.fastq_2)) }
// Channel operators
filtered = reads_ch
.filter { id, files -> id.startsWith("ctrl") }
.view { id, files -> "Processing: ${id}" }
}
Module 3: Workflow Block — Pipeline DAG Definition
Connect processes with channels to define the pipeline DAG.
nextflow.enable.dsl = 2
include { FASTP } from './modules/fastp'
include { STAR_ALIGN } from './modules/star'
include { FEATURECOUNTS } from './modules/featurecounts'
workflow RNA_SEQ {
take:
reads_ch // tuple: [sample_id, [R1, R2]]
genome_idx // path: STAR index directory
gtf // path: annotation GTF file
main:
// Trim reads
FASTP(reads_ch)
// Align trimmed reads
STAR_ALIGN(FASTP.out.reads, genome_idx)
// Count reads (join on sample_id)
FEATURECOUNTS(STAR_ALIGN.out.bam, gtf)
emit:
counts = FEATURECOUNTS.out.counts
logs = STAR_ALIGN.out.log.mix(FASTP.out.log)
}
workflow {
reads = Channel.fromFilePairs("data/*_{R1,R2}.fastq.gz")
genome_idx = Channel.value(file("genome/star_index"))
gtf = Channel.value(file("genome/annotation.gtf"))
RNA_SEQ(reads, genome_idx, gtf)
RNA_SEQ.out.counts | view
}
Module 4: Configuration — Profiles for Different Environments
Configure execution profiles for local, HPC, and cloud environments.
// nextflow.config — profile-based configuration
profiles {
local {
process.executor = 'local'
process.cpus = 4
process.memory = '8 GB'
docker.enabled = true
}
slurm {
process.executor = 'slurm'
process.queue = 'batch'
process.clusterOptions = '--account=myproject'
singularity.enabled = true
singularity.autoMounts = true
// Per-process resource configuration
process {
withName: STAR_ALIGN {
cpus = 16
memory = '32 GB'
time = '4h'
}
withName: FASTP {
cpus = 8
memory = '8 GB'
}
}
}
aws {
process.executor = 'awsbatch'
process.queue = 'arn:aws:batch:us-east-1:123456789:job-queue/my-queue'
aws.region = 'us-east-1'
aws.batch.cliPath = '/home/ec2-user/miniconda/bin/aws'
docker.enabled = true
}
}
// Global params
params {
outdir = 'results'
genome = 'GRCh38'
max_cpus = 16
max_memory = '128 GB'
max_time = '72h'
}
Module 5: Operators — Channel Transformations
Transform channels using built-in operators.
nextflow.enable.dsl = 2
workflow {
// Map: transform each element
Channel.fromPath("data/*.fastq.gz")
.map { file -> tuple(file.baseName.replaceAll(/_R[12]/, ''), file) }
.groupTuple() // group by sample_id → [sample_id, [R1, R2]]
.view { id, files -> "Sample: ${id} (${files.size()} files)" }
// Filter by condition
Channel.of(1, 2, 3, 4, 5)
.filter { it > 3 }
.view() // emits: 4, 5
// Combine channels
samples = Channel.of('A', 'B', 'C')
refs = Channel.value(file("genome.fa"))
samples.combine(refs).view() // [A, genome.fa], [B, genome.fa], [C, genome.fa]
// Collect all outputs into a list
Channel.of(1, 2, 3).collect().view() // [[1, 2, 3]]
}
Module 6: Error Handling and Resuming
Handle failures, retry strategies, and pipeline resuming.
// nextflow.config — retry and error handling
process {
// Retry failed processes up to 3 times with increasing memory
errorStrategy = { task.exitStatus in [137, 140] ? 'retr