RNA-Seq QC Pipeline with Nextflow
Build a modular Nextflow DSL2 pipeline to automate RNA-Seq quality control.
Introduction
30 Second Summary
When you run an RNA sequencing experiment, you get millions of short reads that might contain adapter contamination, low-quality bases, or sequencing errors. Before any downstream analysis, you need a reliable quality control pipeline that catches these problems early.
In this project, you will build a modular RNA-Seq QC pipeline from scratch using Nextflow DSL2. You'll wire together three containerized bioinformatics tools and produce a consolidated quality report with a single command.
What You'll Build
Run one command and watch Nextflow orchestrate FastQC, Trim Galore, and MultiQC in sequence, then open a polished HTML report showing your read quality before and after adapter trimming.
By the end of this project, you'll have:
- A working pipeline that processes raw FASTQ files through quality control, adapter trimming, and report aggregation using Docker containers you never have to install manually.
- A modular project structure where each bioinformatics tool lives in its own Nextflow module file, making your pipeline easy to extend or share with collaborators.
- A GitHub repository with proper pipeline structure including test data, configuration, and documentation that others can clone and run immediately.
- Secret Mission: Extend the pipeline to accept a CSV samplesheet and process multiple samples in parallel using Nextflow's dataflow paradigm.
Are there any prerequisites?
This project assumes you're comfortable with the Linux command line and WSL (Windows Subsystem for Linux). You should also be familiar with bioinformatics QC tools like FastQC, Trim Galore, and MultiQC at a conceptual level.
Before We Start
Before We Start...
Before we dive in, let's lock in what you're about to build and why it matters for your bioinformatics work.
Set Up Your Environment
Nextflow requires Java 17 or later to run. Your current Java 11 installation is explicitly unsupported, so the pipeline will refuse to start until you upgrade.
In this step, you will upgrade Java via SDKMAN!, install Nextflow, verify that Docker is accessible from WSL, and create the project directory structure.
In this step, get ready to:
- Upgrade Java to 17 using SDKMAN! so Nextflow can run.
- Install Nextflow and confirm it works.
- Create the pipeline project folder and connect it to GitHub.
Upgrade Java to 17 via SDKMAN!
SDKMAN! is a version manager for Java and other JVM tools. It lets you install and switch between Java versions without conflicting with your system install.
- Install SDKMAN! in your WSL terminal by running this command:
curl -s "https://get.sdkman.io" | bash
What does this command do?
This downloads and runs the SDKMAN! installer. It creates a .sdkman directory in your home folder and configures shell integration.
At the end of the install, SDKMAN! tells you to open a new terminal or source its init script. You will do that next.
- Activate SDKMAN! in your current session by running:
source "$HOME/.sdkman/bin/sdkman-init.sh"
- Install Java 17 Temurin by running:
sdk install java 17.0.19-tem
What does this command do?
SDKMAN! downloads Eclipse Temurin JDK 17.0.19 and sets it as your active Java version. Temurin is a popular, open-source OpenJDK distribution.
Before you verify, what version do you expect java -version to report now?
- Confirm the upgrade worked by running:
java -version
✔️ I see OpenJDK 17
You should see output containing openjdk version "17.0.19" or similar. Java is ready for Nextflow.
ⓧ I see a different Java version
SDKMAN! may not have set 17 as the default. Run:
sdk use java 17.0.19-tem
Then run java -version again to confirm it now shows 17.
ⓧ Command not found
Your shell may not have sourced the SDKMAN! init script. Close your terminal, open a new WSL session, and run:
source "$HOME/.sdkman/bin/sdkman-init.sh"
java -version
If you still see an error, check that ~/.sdkman exists. If it does not, re-run the SDKMAN! install command from above.
Install Nextflow
Nextflow is the workflow engine that orchestrates your pipeline. It uses Java under the hood, which is why you upgraded first.
- Download the Nextflow binary by running:
curl -s https://get.nextflow.io | bash
What does this command do?
This downloads the latest stable Nextflow release as a self-contained executable file called nextflow in your current directory. It also verifies your Java version is compatible.
- Make the binary executable and move it to a directory on your PATH by running:
chmod +x nextflow
mkdir -p $HOME/.local/bin
mv nextflow $HOME/.local/bin/
- Ensure $HOME/.local/bin is on your PATH. Add the export line to your ~/.bashrc and reload it by running:
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc
source ~/.bashrc
Already have this in your PATH?
If $HOME/.local/bin is already in your PATH, running the command above adds a duplicate entry. This is harmless but unnecessary. You can check first with echo $PATH and skip this step if you see the directory listed.
What do you expect to see when you run nextflow info? Think about what details a workflow engine would report about itself.
- Verify Nextflow is installed by running:
nextflow info
✔️ I see Nextflow version and runtime info
You should see output showing the Nextflow version, build number, your operating system, and the Java runtime. This confirms Nextflow is installed and can find Java 17.
ⓧ Command not found
The nextflow binary is not on your PATH. Verify it exists:
ls $HOME/.local/bin/nextflow
If the file is there, add the directory to your PATH:
export PATH="$PATH:$HOME/.local/bin"
nextflow info
Make this permanent by adding the export line to your ~/.bashrc file.
Seeing a Java version error?
If Nextflow complains about an unsupported Java version, it is picking up your old Java 11 instead of the SDKMAN!-managed version. Run java -version to check. If it shows Java 11, activate SDKMAN! again:
source "$HOME/.sdkman/bin/sdkman-init.sh"
java -version
Then retry nextflow info.
Help me fix this Java version error
Verify Docker and initialize the project
Nextflow will pull Docker containers for each bioinformatics tool in the pipeline. Docker Desktop must be accessible from inside WSL for this to work.
- Confirm Docker is accessible from WSL by running:
docker run hello-world
✔️ I see "Hello from Docker!"
Docker is working inside WSL. You are ready to create your project.
ⓧ I see an error
The most common cause is Docker Desktop not running, or WSL integration not enabled.
- Open Docker Desktop on Windows.
- Go to Settings then Resources then WSL integration.
- Ensure your Ubuntu distribution is enabled.
- Click Apply & restart.
- Return to your WSL terminal and retry docker run hello-world.
Help me fix Docker in WSL
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir rnaseq-qc-pipeline && cd rnaseq-qc-pipeline
- Create the subdirectories and initialize a Git repository by running:
mkdir modules data results
git init
- Confirm the project structure by running:
ls
You should see three directories listed: data, modules, and results.
What is this project structure?
This follows the standard Nextflow pipeline layout. modules/ holds individual process definitions. data/ stores your test FASTQ files. results/ is where the pipeline publishes its outputs.
- Create a new repository on GitHub. Go to github.com/new in your browser.
- Name the repository rnaseq-qc-pipeline.
- Leave it as Public and do not initialize with a README (you will push your local repo).
- Click Create repository.
- Connect your local repository to GitHub by running this command (replace the URL with your own):
git remote add origin [[YOUR_REPO_URL="https://github.com/YOUR_USERNAME/rnaseq-qc-pipeline.git"]]
Don't have a GitHub account?
Create a free account at github.com. After creating the repository, GitHub shows you the exact remote URL to use.
Help me connect my repo to GitHub
Your environment is ready. You have Java 17, Nextflow, Docker access, and a clean project structure connected to GitHub.
Next up, you will write your first Nextflow process and watch it run FastQC on a real FASTQ file.
Write Your First Process and See It Run
Your environment is ready with Nextflow, Java 17, and Docker all confirmed working. Now you need to see Nextflow actually do something before layering on complexity.
A single FastQC process on one FASTQ file demonstrates how processes, channels, and container directives work together. By the end of this step you will have a running pipeline that produces a real QC report.
In this step, get ready to:
- Download a test FASTQ file into your project.
- Write a FastQC process module and a main workflow that calls it.
- Run the pipeline and confirm it produces an HTML quality report.
Add test FASTQ data
Every pipeline needs input data to process. You will download a small, sub-sampled RNA-Seq FASTQ file from the nf-core test datasets repository.
- Download the test file into your data/ directory by running this command:
curl -fsSL https://raw.githubusercontent.com/nf-core/test-datasets/rnaseq/testdata/GSE110004/SRR6357070_1.fastq.gz -o data/sample1_R1.fastq.gz
- Confirm the file downloaded by running:
ls -lh data/
You should see sample1_R1.fastq.gz listed with a file size of around 6-7 MB.
Download failed or file is 0 bytes?
Make sure you are inside the rnaseq-qc-pipeline directory before running the curl command. If the download times out, check your internet connection and try again.
help me troubleshoot my curl download failing
Create the FastQC module
In Nextflow DSL2, each tool lives in its own module file. This keeps your pipeline organized and each process reusable.
- Create and open a new file called modules/fastqc.nf in VS Code, then paste in the following code:
process FASTQC {
container "biocontainers/fastqc:v0.12.1_cv2"
publishDir "${params.outdir}/fastqc", mode: 'copy'
input:
path reads
output:
path "*_fastqc.zip", emit: zip
path "*_fastqc.html", emit: html
script:
"""
fastqc $reads
"""
}
What does this code do?
- container tells Nextflow to run this process inside a Docker image that already has FastQC installed.
- publishDir copies the final outputs to results/fastqc/ so you can inspect them after the run.
- emit: zip and emit: html give each output a name, so downstream processes can reference them as FASTQC.out.zip and FASTQC.out.html.
- Save modules/fastqc.nf.
Create the main workflow and config
The main workflow file ties everything together. It declares parameters, imports modules, and defines the execution order through channels.
- Create and open main.nf in the root of your rnaseq-qc-pipeline folder, then paste in this code:
#!/usr/bin/env nextflow
/*
* RNA-Seq QC Pipeline
* Performs quality control, adapter trimming, and report aggregation
*/
params.reads = "$baseDir/data/sample1_R1.fastq.gz"
params.outdir = "results"
include { FASTQC } from './modules/fastqc.nf'
workflow {
// Create input channel from file path
read_ch = Channel.fromPath(params.reads, checkIfExists: true)
// Run initial quality control
FASTQC(read_ch)
}
What does this code do?
- params.reads sets a default input path that the learner can override from the command line with --reads.
- Channel.fromPath(...) creates a Nextflow channel from the file path. Channels are how data flows between processes.
- checkIfExists: true makes the pipeline fail fast with a clear error if the input file is missing.
- include { FASTQC } imports your module so the workflow block can call it.
Nextflow also needs a configuration file to know that it should use Docker for containers.
- Create and open nextflow.config in the project root, then paste:
profiles {
docker {
docker.enabled = true
}
}
- Save both main.nf and nextflow.config.
- Confirm all your pipeline files are in place by running:
ls modules/fastqc.nf main.nf nextflow.config
You should see all three file names printed without errors.
✔️ Awesome, I've got everything!
Great. Make sure you have saved all three files before continuing.
ⓧ I'd like to double check the full code
Here is the full modules/fastqc.nf:
process FASTQC {
container "biocontainers/fastqc:v0.12.1_cv2"
publishDir "${params.outdir}/fastqc", mode: 'copy'
input:
path reads
output:
path "*_fastqc.zip", emit: zip
path "*_fastqc.html", emit: html
script:
"""
fastqc $reads
"""
}
Here is the full main.nf:
#!/usr/bin/env nextflow
/*
* RNA-Seq QC Pipeline
* Performs quality control, adapter trimming, and report aggregation
*/
params.reads = "$baseDir/data/sample1_R1.fastq.gz"
params.outdir = "results"
include { FASTQC } from './modules/fastqc.nf'
workflow {
// Create input channel from file path
read_ch = Channel.fromPath(params.reads, checkIfExists: true)
// Run initial quality control
FASTQC(read_ch)
}
Here is the full nextflow.config:
profiles {
docker {
docker.enabled = true
}
}
Run the pipeline
Everything is wired up. Time to see if Nextflow can orchestrate FastQC inside a Docker container on your FASTQ file.
Before you run this, what do you expect to happen? Will Nextflow download the Docker image automatically, or will it fail because FastQC is not installed locally?
- Execute the pipeline by running:
nextflow run main.nf -profile docker --reads 'data/sample1_R1.fastq.gz'
Nextflow pulls the Docker image on the first run, then executes the FASTQC process. You should see progress output showing the FASTQC process completing with a green checkmark.
What should I see?
Nextflow prints a progress bar for each process. When FASTQC finishes you will see something like:
executor > local (1) followed by [hash] process > FASTQC (1) [100%] 1 of 1 with a checkmark. The first run takes longer because Docker pulls the FastQC image.
- Check that the HTML report was created by running:
ls results/fastqc/
You should see a .html file and a .zip file listed. The HTML file is the FastQC quality report you can open in your browser.
Pipeline failed or no output files?
- If you see a Docker-related error, make sure Docker Desktop is running and accessible from WSL. Run docker ps to confirm Docker is responsive.
- If you see a file-not-found error for the reads, double-check that data/sample1_R1.fastq.gz exists and is not 0 bytes.
- If the process hangs on the image pull, check your internet connection. The first pull can take a minute or two.
help me debug my Nextflow pipeline failing on the FASTQC process
You just ran a real bioinformatics pipeline with a single command. Next up, you will add adapter trimming and learn how to chain processes together using Nextflow channels.
Add Trimming and Chain Processes Together
In Step 2 you built a pipeline that reports on your data quality. That is valuable, but it does not fix any problems it finds.
Adapter contamination and low-quality bases degrade downstream analyses like alignment and quantification. Trim Galore handles both: it trims adapters, removes low-quality tails, and can run FastQC on the trimmed output in one pass. In this step you will create a Trim Galore process module and wire it into your workflow alongside FASTQC.
In this step, get ready to:
- Create a TRIM_GALORE process module with container, inputs, and named outputs.
- Wire the new module into your main workflow so both processes run on the same input channel.
- Run the pipeline and confirm trimmed reads appear in the results directory.
Create the Trim Galore module
Your pipeline needs a second process that trims adapters and low-quality bases from reads. You will define it in its own module file, following the same pattern you used for modules/fastqc.nf.
- Create a new file called modules/trim_galore.nf in your rnaseq-qc-pipeline project and paste the following code:
process TRIM_GALORE {
container "community.wave.seqera.io/library/trim-galore:0.6.10--1bf8ca4e1967cd18"
publishDir "${params.outdir}/trimming", mode: 'copy'
input:
path reads
output:
path "*_trimmed.fq.gz", emit: trimmed_reads
path "*_trimming_report.txt", emit: trimming_reports
path "*_trimmed_fastqc.{zip,html}", emit: fastqc_reports
script:
"""
trim_galore --fastqc $reads
"""
}
What does this code do?
- container pulls a pre-built image from Seqera's Wave registry that bundles both Trim Galore and FastQC. No local install required.
- publishDir copies outputs to results/trimming/ so you can inspect them outside the Nextflow work directory.
- The --fastqc flag tells Trim Galore to automatically run FastQC on the trimmed output. This gives you post-trim QC reports alongside the trimmed reads.
- Each output line uses a named emit so downstream processes can reference specific outputs like TRIM_GALORE.out.trimmed_reads.
- Save modules/trim_galore.nf.
- Confirm the file exists by running:
ls modules/
You should see both fastqc.nf and trim_galore.nf listed.
Only see fastqc.nf?
Make sure you created the file inside the modules/ directory, not in the project root. The filename must be exactly trim_galore.nf (with an underscore, not a hyphen).
Help me find where my trim_galore.nf file ended up.
Wire Trim Galore into the workflow
The module file defines what TRIM_GALORE does, but your workflow does not know about it yet. You need to import the module and call it on the same input channel that feeds FASTQC.
- Open main.nf and find this existing import line:
include { FASTQC } from './modules/fastqc.nf'
- Add the TRIM_GALORE import directly below it, so the two lines look like this:
include { FASTQC } from './modules/fastqc.nf'
include { TRIM_GALORE } from './modules/trim_galore.nf'
- Scroll down to the workflow block and find these lines:
// Run initial quality control
FASTQC(read_ch)
- Add the TRIM_GALORE call directly below it:
// Trim adapters and run post-trimming QC
TRIM_GALORE(read_ch)
Why the same channel?
Both FASTQC and TRIM_GALORE receive read_ch as input. In Nextflow, a channel can be consumed by multiple processes. Each process gets its own copy of the data and runs independently.
This means FASTQC and TRIM_GALORE can execute in parallel if resources allow. Neither waits for the other to finish.
- Save main.nf.
✔️ Awesome, I've got everything!
Great. Double check you have saved both modules/trim_galore.nf and main.nf.
ⓧ I'd like to double check the full code
Here is the complete main.nf at this point:
#!/usr/bin/env nextflow
/*
* RNA-Seq QC Pipeline
* Performs quality control, adapter trimming, and report aggregation
*/
params.reads = "$baseDir/data/sample1_R1.fastq.gz"
params.outdir = "results"
include { FASTQC } from './modules/fastqc.nf'
include { TRIM_GALORE } from './modules/trim_galore.nf'
workflow {
// Create input channel from file path
read_ch = Channel.fromPath(params.reads, checkIfExists: true)
// Run initial quality control
FASTQC(read_ch)
// Trim adapters and run post-trimming QC
TRIM_GALORE(read_ch)
}
And the complete modules/trim_galore.nf:
process TRIM_GALORE {
container "community.wave.seqera.io/library/trim-galore:0.6.10--1bf8ca4e1967cd18"
publishDir "${params.outdir}/trimming", mode: 'copy'
input:
path reads
output:
path "*_trimmed.fq.gz", emit: trimmed_reads
path "*_trimming_report.txt", emit: trimming_reports
path "*_trimmed_fastqc.{zip,html}", emit: fastqc_reports
script:
"""
trim_galore --fastqc $reads
"""
}
Run the pipeline and verify trimming output
Before you run the pipeline, what do you expect to see in the Nextflow output? Will both processes run, or just one?
- Run the updated pipeline:
nextflow run main.nf -profile docker --reads 'data/sample1_R1.fastq.gz'
You should see Nextflow's progress output showing both the FASTQC and TRIM_GALORE processes completing successfully. Each line shows the process name and a checkmark when it finishes.
- Check the trimming results by running:
ls results/trimming/
You should see trimmed FASTQ files (*_trimmed.fq.gz), a trimming report (*_trimming_report.txt), and post-trim FastQC reports (*_trimmed_fastqc.html and *_trimmed_fastqc.zip).
Seeing a process failure?
- If TRIM_GALORE fails with a container error, make sure Docker Desktop is running and accessible from WSL. Run docker ps to confirm Docker responds.
- If you see a file-not-found error, check that data/sample1_R1.fastq.gz still exists in your project directory.
- If the container image fails to pull, check your internet connection. The Seqera Wave image is around 200 MB.
Help me debug my TRIM_GALORE process failure.
Your pipeline now runs two processes: one to assess quality, and one to fix it. Next up, you will aggregate all the QC reports into a single consolidated view with MultiQC.
Aggregate Reports with MultiQC
Your pipeline now produces FastQC reports in one directory and Trim Galore reports in another. To understand your data quality at a glance, you need all those metrics combined in a single view.
In this step, you will create a MultiQC module that aggregates every QC report into one HTML dashboard. Along the way, you will learn two essential Nextflow channel operators: .mix() to merge outputs from different processes, and .collect() to gather everything into a single list for a downstream process.
In this step, get ready to:
- Create a MultiQC module with container and publish directives.
- Wire report channels together using mix and collect operators.
- Run the full pipeline and open the consolidated HTML report.
Create the MultiQC module
MultiQC scans a directory for recognized QC output files and combines them into a single interactive HTML report. You will define it as its own module file so the pipeline stays modular.
- Create the modules/multiqc.nf file by running:
touch modules/multiqc.nf
- Confirm the file exists by running:
ls modules/
You should see fastqc.nf, trim_galore.nf, and multiqc.nf listed.
- Open modules/multiqc.nf in VS Code and paste the following process definition:
process MULTIQC {
container "multiqc/multiqc:latest"
publishDir "${params.outdir}/multiqc", mode: 'copy'
input:
path '*'
output:
path "multiqc_report.html", emit: report
path "multiqc_data", emit: data
script:
"""
multiqc .
"""
}
What does this code do?
- container "multiqc/multiqc:latest" tells Nextflow to pull the official MultiQC Docker image to run this process.
- path '*' as the input accepts all staged files. Nextflow stages every file from the input channel into this process's working directory.
- multiqc . scans the current directory for recognized QC tool outputs and generates an aggregated HTML report plus a data directory.
- The two named emits (report and data) let you reference each output individually downstream if needed.
- Save modules/multiqc.nf.
File not saving?
Make sure you created the file inside the modules/ directory and not in the project root. Run ls modules/multiqc.nf to confirm it exists in the right place.
Help me find my multiqc.nf file
Wire MultiQC into the workflow using mix and collect
The MULTIQC process needs reports from both FASTQC and TRIM_GALORE. You will merge their output channels with .mix() and then gather them into a single list with .collect() so MultiQC receives everything at once.
- In main.nf, find the existing import lines near the top of the file:
include { FASTQC } from './modules/fastqc.nf'
include { TRIM_GALORE } from './modules/trim_galore.nf'
- Add the MULTIQC import directly below those two lines, so all three imports look like this:
include { FASTQC } from './modules/fastqc.nf'
include { TRIM_GALORE } from './modules/trim_galore.nf'
include { MULTIQC } from './modules/multiqc.nf'
- Now scroll down to the workflow block. Find the line that calls TRIM_GALORE:
// Trim adapters and run post-trimming QC
TRIM_GALORE(read_ch)
- Add the following code directly below it, still inside the workflow { } block:
// Aggregate all QC reports into a single report
multiqc_ch = Channel.empty()
.mix(FASTQC.out.zip, TRIM_GALORE.out.trimming_reports, TRIM_GALORE.out.fastqc_reports)
.collect()
MULTIQC(multiqc_ch)
What do mix and collect do here?
Channel.empty().mix() creates an empty channel and merges three separate output channels into it. Each output channel carries a different type of QC report file.
.collect() waits for all items from the merged channel to arrive, then bundles them into a single list. Without .collect(), MultiQC would run once per file instead of once on all files together.
MULTIQC(multiqc_ch) passes the collected list to your MULTIQC process. Nextflow stages every report into its working directory, and multiqc . scans them all to produce the aggregated report.
- Save main.nf.
✔️ Awesome, I've got everything!
Great. Double check you saved both modules/multiqc.nf and main.nf.
ⓧ I'd like to double check the full code
Here is the complete modules/multiqc.nf:
process MULTIQC {
container "multiqc/multiqc:latest"
publishDir "${params.outdir}/multiqc", mode: 'copy'
input:
path '*'
output:
path "multiqc_report.html", emit: report
path "multiqc_data", emit: data
script:
"""
multiqc .
"""
}
Here is the complete main.nf:
#!/usr/bin/env nextflow
/*
* RNA-Seq QC Pipeline
* Performs quality control, adapter trimming, and report aggregation
*/
params.reads = "$baseDir/data/sample1_R1.fastq.gz"
params.outdir = "results"
include { FASTQC } from './modules/fastqc.nf'
include { TRIM_GALORE } from './modules/trim_galore.nf'
include { MULTIQC } from './modules/multiqc.nf'
workflow {
// Create input channel from file path
read_ch = Channel.fromPath(params.reads, checkIfExists: true)
// Run initial quality control
FASTQC(read_ch)
// Trim adapters and run post-trimming QC
TRIM_GALORE(read_ch)
// Aggregate all QC reports into a single report
multiqc_ch = Channel.empty()
.mix(FASTQC.out.zip, TRIM_GALORE.out.trimming_reports, TRIM_GALORE.out.fastqc_reports)
.collect()
MULTIQC(multiqc_ch)
}
Run the full pipeline and view the report
You have three processes wired together now. Before you run the pipeline, what do you expect to see in Nextflow's output? Will all three processes complete?
- Run the complete pipeline by executing:
nextflow run main.nf -profile docker --reads 'data/sample1_R1.fastq.gz'
You should see Nextflow's progress output showing all three processes completing: FASTQC, TRIM_GALORE, and MULTIQC.
- Confirm the MultiQC output was published by running:
ls results/multiqc/
You should see multiqc_report.html and a multiqc_data directory listed.
- Open the report in your Windows browser. From WSL, you can use explorer.exe to open the folder containing the report:
explorer.exe results/multiqc/
- In the Windows File Explorer window that opens, double-click multiqc_report.html to open it in your browser.
The MultiQC report shows both pre-trim and post-trim quality metrics side by side. You can compare raw read quality from FastQC against the cleaned-up metrics after Trim Galore ran.
MULTIQC process failing?
- Make sure Docker Desktop is running. Nextflow needs it to pull the multiqc/multiqc:latest image.
- Check that the input: line in your modules/multiqc.nf reads path '*' with quotes around the asterisk. A missing quote causes a syntax error.
- If you see an empty MultiQC report, verify the .mix() line references the correct named emits: FASTQC.out.zip, TRIM_GALORE.out.trimming_reports, and TRIM_GALORE.out.fastqc_reports.
Help me debug my MULTIQC process
Your pipeline now runs end-to-end, from raw reads to a consolidated quality report, all orchestrated by Nextflow. Next up, you will push this project to GitHub so it is shareable and reproducible.
Push to GitHub
Your pipeline runs end-to-end, pulling containers and producing a consolidated MultiQC report from a single command.
A pipeline that only lives on your local machine is not shareable or reproducible. Pushing to GitHub with a proper README.md and .gitignore turns this into a portfolio-ready project that anyone can clone and run.
In this step, get ready to:
- Create a .gitignore and README.md for the project.
- Commit and push the full project to GitHub.
Create .gitignore and README
Nextflow generates large intermediate files in its work/ directory that should never end up in version control. A .gitignore keeps those out, and a README.md tells anyone who finds your repo how to run the pipeline.
- Create a new file called .gitignore in the root of your rnaseq-qc-pipeline folder and paste in the following content:
work/
.nextflow/
.nextflow.log*
results/
What does this exclude?
- work/ contains all the intermediate files Nextflow creates while running each process task.
- .nextflow/ and .nextflow.log* hold Nextflow's internal cache and execution logs.
- results/ holds the published output files. Anyone cloning the repo can regenerate these by running the pipeline.
- Create another file called README.md in the root of your rnaseq-qc-pipeline folder and paste in the following content:
# RNA-Seq QC Pipeline
A modular Nextflow DSL2 pipeline for RNA-Seq quality control.
## Pipeline Steps
1. **FastQC** - Initial quality control on raw reads
2. **Trim Galore** - Adapter trimming with post-trim QC
3. **MultiQC** - Aggregated quality report
## Prerequisites
- Nextflow 26.04+
- Docker
- Java 17+
## Usage
```bash
nextflow run main.nf -profile docker --reads 'data/sample1_R1.fastq.gz'
```
## Output
Results are published to the `results/` directory:
- `results/fastqc/` - Raw read QC reports
- `results/trimming/` - Trimmed reads and trimming reports
- `results/multiqc/` - Consolidated HTML report
What does this README cover?
A good pipeline README answers four questions: what does it do, what do I need, how do I run it, and what will I get.
The Prerequisites section lists the exact version requirements (Nextflow 26.04+, Docker, Java 17+) so anyone cloning knows exactly what to install.
- Save both files.
- Confirm the new files exist by running:
ls -a
You should see .gitignore and README.md listed alongside your existing files (main.nf, modules/, data/, nextflow.config).
Don't see .gitignore in the listing?
Files starting with a dot are hidden by default. Make sure you ran ls -a (with the -a flag) to show all files including hidden ones.
If the file is missing entirely, check that you created it in the rnaseq-qc-pipeline directory and not inside a subfolder.
Help me troubleshoot my missing .gitignore file.
Commit and push to GitHub
With the documentation files in place, you can stage everything and push the complete pipeline to your remote repository.
- Stage all project files by running:
git add .
- Commit with a descriptive message by running:
git commit -m "Initial commit: RNA-Seq QC pipeline with FastQC, Trim Galore, and MultiQC"
You should see a summary listing all the files committed (including main.nf, the three module files, nextflow.config, .gitignore, README.md, and the test FASTQ file).
- Push the commit to GitHub by running:
git push -u origin main
Seeing a rejected or authentication error?
If you see an authentication failure, confirm your Git credentials are configured in WSL. GitHub now requires a personal access token or SSH key for push access.
If the push is rejected because the remote has content you do not have locally (like an auto-generated README), pull first with git pull --rebase origin main and then push again.
Help me fix my git push error.
Before you check GitHub, what do you expect to see in the repository? Think about which files should appear and which ones the .gitignore excluded.
- Visit your GitHub repository URL in your browser.
You should see the full project structure: main.nf, modules/, data/, nextflow.config, .gitignore, and README.md.
The README renders below the file listing, showing the pipeline steps, prerequisites, usage command, and output locations. The work/ and results/ directories are nowhere to be found. That is your .gitignore doing its job.
✔️ Awesome, I've got everything!
Great. Double check that you see all the expected files on GitHub and that the rendered README matches what you wrote.
ⓧ I'd like to double check the full code
Scroll up and confirm these files match what you created:
- .gitignore with four exclusion patterns.
- README.md with Pipeline Steps, Prerequisites, Usage, and Output sections.
All other project files (main.nf, the three module files, nextflow.config) were created in earlier steps and should already be present in your project folder.
Secret mission
Multi-Sample Parallel Processing
Real RNA-Seq experiments have dozens of samples, not just one. Can you extend your pipeline to read from a CSV samplesheet and process multiple samples in parallel? This is where Nextflow's dataflow paradigm truly shines.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally with free tools and a free GitHub repository, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- rnaseq-qc-pipeline project directory on your Desktop (source code, test data, pipeline files).
- Nextflow work/ directory (intermediate task files, can grow large).
- Docker images pulled to your local Docker cache (FastQC, Trim Galore, MultiQC containers).
- GitHub repository (free, no ongoing cost).
- Nextflow binary installed at $HOME/.local/bin/nextflow.
- SDKMAN! and Java 17 installed at ~/.sdkman.
Keep everything running
No action needed. Choose this if you plan to keep developing your pipeline or want to reuse these tools for future Nextflow projects.
- Your project files, Docker images, Nextflow, and SDKMAN! all remain on your machine.
- Docker images take up disk space but incur no cost. You can prune unused images later with docker image prune.
- The work/ directory stores Nextflow's intermediate files and can grow large. Remove it anytime with rm -rf work/ from inside your project folder without affecting your pipeline code.
Pause - I'll come back to this later
Free up disk space while keeping your source code and tools intact. You can re-run the pipeline anytime and Nextflow will re-download what it needs.
- Remove the Nextflow work directory and results to reclaim disk space. Run this from inside your rnaseq-qc-pipeline folder:
rm -rf work/ results/
- Prune Docker images you no longer need:
docker image prune
- Your pipeline source code, modules, test data, and GitHub remote remain untouched. Run nextflow run main.nf -profile docker again whenever you want to resume.
Delete - I don't want to use this again
Remove all project resources and tools installed during this project. Follow each step that applies to you.
- Delete the project directory. Run this from your Desktop:
cd ~/Desktop
rm -rf rnaseq-qc-pipeline
- Remove Docker images pulled during this project:
docker image prune
- Remove the Nextflow binary:
rm $HOME/.local/bin/nextflow
- Uninstall Java 17 via SDKMAN!:
sdk uninstall java 17.0.19-tem
- Remove SDKMAN! entirely by deleting its installation directory:
rm -rf ~/.sdkman
- Open your ~/.bashrc file and remove the SDKMAN! initialization snippet (the block that starts with #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!).
- Delete the GitHub repository. Navigate to your repository on GitHub, click Settings, scroll to the Danger Zone section, and click Delete this repository. Confirm by typing the repository name.
Nice Work!
Nice Work!
Nice work! You just built a production-ready RNA-Seq quality control pipeline from scratch using Nextflow DSL2.
You've learned how to:
- Built a modular Nextflow DSL2 pipeline from scratch, with each bioinformatics process (FastQC, Trim Galore, MultiQC) defined in its own reusable module file.
- Wired processes together using Nextflow channels and channel operators (.mix() and .collect()) to aggregate QC outputs from multiple processes into a single consolidated MultiQC report.
- Ran containerized bioinformatics tools through Docker without installing them locally, and published the pipeline to GitHub with proper project structure including modules, config, test data, and a README.
- Secret Mission: Extended the pipeline to process multiple samples in parallel from a CSV samplesheet using splitCsv and tuple channels.
Ready to quiz yourself?