Filters reads by quality, length, N content, and complexity with Trimmomatic, fastp, and Cutadapt, including sliding-window trimming, per-read unqualified-base filtering, and 2-color poly-G removal. Use when reads have poor-quality tails, when an assembly or k-mer workflow needs clean input, or when a junk read subpopulation must be dropped. For adapter removal use adapter-trimming; for all-in-one preprocessing use fastp-workflow.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add FridrichMethod/awesome-skills --skill quality-filtering --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Quality Filtering?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/fridrichmethod-quality-filtering)More formats (shields.io, HTML) on the badges page.
---
name: bio-read-qc-quality-filtering
description: Filters reads by quality, length, N content, and complexity with Trimmomatic, fastp, and Cutadapt, including sliding-window trimming, per-read unqualified-base filtering, and 2-color poly-G removal. Use when reads have poor-quality tails, when an assembly or k-mer workflow needs clean input, or when a junk read subpopulation must be dropped. For adapter removal use adapter-trimming; for all-in-one preprocessing use fastp-workflow.
tool_type: cli
primary_tool: trimmomatic
---
## Version Compatibility
Reference examples tested with: Trimmomatic 0.39+, fastp 0.23+, Cutadapt 4.4+
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.
# Quality Filtering -- trim lightly or not at all, and never without a length filter
Trim low-quality bases and drop low-quality reads with Trimmomatic (sliding window / MAXINFO), fastp (per-read filter + window cut), or Cutadapt (BWA-style quality trim).
**"Filter reads by quality"** -> Remove low-quality bases and/or discard reads below quality/length thresholds.
- CLI: `fastp -i in.fq -o out.fq --cut_right -q 20 -l 36` (window trim + per-read filter + length gate)
- CLI: `trimmomatic SE in.fq out.fq SLIDINGWINDOW:4:20 MINLEN:36`
Scope: this skill OWNS quality/length/N/complexity filtering. Adapter removal -> read-qc/adapter-trimming. Single-pass trim+QC -> read-qc/fastp-workflow. Reading the quality plots -> read-qc/quality-reports. OUT OF SCOPE: contamination removal (read-qc/contamination-screening).
## The Single Most Important Modern Insight
1. **Modern local aligners SOFT-CLIP low-quality tails, so quality trimming is usually unnecessary -- and AGGRESSIVE quality trimming actively harms downstream results.** Williams 2016 showed aggressive trimming changed expression estimates for >10% of genes; Del Fabbro 2013 showed stringent Q>30 DEGRADES de novo assembly; MacManes 2014 found gentle trimming (remove only Phred<2-5) optimal for RNA-seq; GATK discourages quality trimming because BQSR recalibrates qualities itself. Trim ADAPTER always (read-qc/adapter-trimming); quality-trim lightly or not at all before a soft-clipping aligner. The workflows that genuinely need quality trimming are assembly, k-mer/pseudo-alignment, small-RNA, amplicon, and variant calling WITHOUT BQSR.
2. **Quality FILTERING (drop whole reads) and quality TRIMMING (cut bases within a read) are different operations with different tools.** fastp's `-q/-u/-n` filters whole reads by the fraction of unqualified bases; `--cut_right` / Trimmomatic `SLIDINGWINDOW` trims bases from a window scan. Filtering removes a junk subpopulation (a low-Q hump in the per-sequence-quality plot); trimming shortens reads with decayed tails. Choose by whether the problem is some bad reads or bad ends.
3. **A short post-trim read mis-maps, so quality trimming MUST be paired with a minimum-length filter.** Williams 2016 showed that adding a post-trim min-length filter mitigates most of the expression distortion that trimming introduces, because over-trimmed fragments that would map spuriously are dropped instead. `MINLEN` (Trimmomatic, always last), `-l` (fastp), `-m` (cutadapt) are not optional add-ons; they are the safety mechanism that makes trimming safe.
Two-color note: on NextSeq/NovaSeq the quality scores are binned to four values (RTA3: 2, 12, 23, 37), so a sliding-window threshold like 4:15 partitions between the 12 and 23 bins rather than acting on a smooth gradient -- thresholds tuned on HiSeq-era 0-40 qualities behave differently. And poly-G tails are HIGH quality, so a quality filter does not remove them (use poly-G trimming).
## Tool Taxonomy
| Tool | Mechanism | When it wins |
|------|-----------|--------------|
| fastp | Per-read unqualified-base filter (`-q/-u/-n`) + window cut (`--cut_right`) + auto poly-G | DEFAULT; one fast pass, filtering and trimming together |
| Trimmomatic | `SLIDINGWINDOW` / `MAXINFO` window trim; ordered step pipeline; orphan handling | Legacy/reproducibility pipelines; MAXINFO length-vs-quality balance |
| Cutadapt | `-q` BWA running-sum quality trim (combined with adapter removal) | When already running cutadapt for adapters; precise per-end control |
## Decision Tree by Scenario
| Workflow | Quality trimming | Why |
|----------|------------------|-----|
| Alignment-based DNA/RNA (BWA-MEM, STAR, Bowtie2 local, HISAT2) | Light or none | Aligner soft-clips tails; aggressive trim distorts expression |
| GATK variant calling with BQSR | None | BQSR recalibrates; trimming interferes |
| De novo assembly | Moderate (~Q20) + min-length | Low-Q errors corrupt the de Bruijn graph; stringent Q>30 over-trims |
| k-mer / pseudo-alignment (kallisto/salmon) | Light + adapter | Errors create phantom k-mers |
| A junk read subpopulation (bimodal per-seq quality) | FILTER whole reads (`-e`/AVGQUAL) | Trimming cannot fix a globally bad read |
| Variant calling WITHOUT BQSR | Moderate + min-length | No recalibration safety net |
Default when uncertain: trim adapter, apply a light window trim plus a minimum-length filter, then confirm with FastQC.
## Trimmomatic
Steps run in COMMAND-LINE ORDER; put quality steps before MINLEN so the length check reflects all trimming.
```bash
# Single-end: light leading/trailing + window, length-gated
trimmomatic SE -phred33 in.fq.gz out.fq.gz \
LEADING:3 TRAILING:3 SLIDINGWINDOW:4:20 MINLEN:36
# Paired-end (four outputs: paired + orphan)
trimmomatic PE -phred33 -threads 8 \
R1.fq.gz R2.fq.gz \
R1_paired.fq.gz R1_unpaired.fq.gz R2_paired.fq.gz R2_unpaired.fq.gz \
SLIDINGWINDOW:4:20 MINLEN:36
# MAXINFO: adaptive length-vs-quality balance (strictness <0.2 favors length, >0.8 favors correctness)
trimmomatic SE in.fq.gz out.fq.gz MAXINFO:40:0.5 MINLEN:36
```
| Step | Meaning |
|------|---------|
| SLIDINGWINDOW:W:Q | scan 5'->3'; cut from the point where the W-bp window mean drops below Q |
| MAXINFO:L:S | adaptive trim balancing target length L against error rate; strictness S in 0-1 |
| LEADING:Q / TRAILING:Q | cut 5'/3' bases below Q (also removes N) |
| MINLEN:L / AVGQUAL:Q | DROP read if shorter than L / if mean quality below Q |
| CROP:L / HEADCROP:N | cap length / remove first N bases (do NOT HEADCROP random-hexamer bias -- see below) |
Do NOT HEADCROP the first ~12 bp of RNA-seq to "fix" the wavy per-base-content plot: that pattern is random-hexamer priming bias (Hansen 2010), not adapter, and trimming it just discards real data without removing the underlying bias.
## fastp
fastp separates per-read FILTERING from window TRIMMING. Quality filtering is on by default (-q 15).
```bash
# Per-read quality filter: base < Q20 is 'unqualified'; drop read if >40% unqualified or >5 Ns
fastp -i in.fq.gz -o out.fq.gz -q 20 -u 40 -n 5 -l 36
# Window trim from the 3' (Trimmomatic SLIDINGWINDOW analogue) + length gate
fastp -i R1.fq.gz -I R2.fq.gz -o R1.fq.gz -O R2.fq.gz \
--cut_right --cut_window_size 4 --cut_mean_quality 20 -l 36
# Drop globally low-quality reads by mean quality (filter, not trim)
fastp -i in.fq.gz -o out.fq.gz -e 25
# 2-color poly-G (auto-enabled for NextSeq/NovaSeq from the instrument ID)
fastp -i in.fq.gz -o out.fq.gz --trim_poly_g
# Low-complexity filter (e.g. poly-A / homopolymer-rich reads)
fastp -i in.fq.gz -o out.fq.gz --low_complexity_filter --complexity_threshold 30
```
fastp flags: `-q` qualified quality (default 15), `-u` unqualified percent limit (default 40), `-n` N base limit (default 5), `-e` average-quality filter (default 0 = off), `-l` length required (default 15), `--length_limit` max length (long form only), `--cut_front/--cut_tail/--cut_right` window cut modes (off by default), `--cut_window_size` (4), `--cut_mean_quality` (Q20).
## Cutadapt
`-q` uses the BWA running-partial-sum algorithm, not a fixed cutoff, so a single high-Q base inside a low-Q run does not stop trimming. Quality trimming runs BEFORE adapter removal.
```bash
# 3'-only quality trim with a length gate (5',3' form: -q 15,20)
cutadapt -q 20 -m 36 -o out.fq.gz in.fq.gz
# Combined adapter + light quality trim, paired
cutadapt -a AGATCGGAAGAGC -A AGATCGGAAGAGC -q 20 -m 36 \
-o R1.fq.gz -p R2.fq.gz R1.fq.gz R2.fq.gz
```
## Quantitative Thresholds
| Parameter | Typical | Rationale |
|-----------|---------|-----------|
| Window quality | Q20 (4:20) | 1% error; light. Aggressive (Q25-30) distorts expression/assembly (Williams 2016, Del Fabbro 2013) |
| fastp -q / -u | Q15 / 40% | fastp defaults; a base under Q15 is unqualified, read dropped if >40% unqualified |
| MINLEN / -l / -m | 36 (150 bp reads) | Mandatory after trimming; short reads mis-map. Scale up for longer inserts |
| complexity_threshold | 30 (30%) | fastp default for low-complexity filtering |
| MAXINFO strictness | 0.2-0.8 | <0.2 favors length, >0.8 favors correctness |
## Common Errors
| Symptom | Cause | Solution |
|---------|-------|----------|
| Expression estimates shift for many genes | Aggressive quality trimming | Trim lightly; always add a min-length filter (Williams 2016) |
| Variant calling worse after trimming | Trimmed before/around BQSR | Do not quality-trim for GATK BQSR workflows |
| Window threshold behaves oddly on NovaSeq | Binned quality (4 values) makes windows coarse | Expect step-like behavior; do not port HiSeq thresholds blindly |
| Reads mis-map after trimming | No min-length filter, over-trimmed fragments | Add MINLEN / -l / -m |
| Poly-G tails survive quality filtering | Poly-G is high quality on 2-color | Use `--trim_poly_g` / cutadapt `--nextseq-trim` |
| R1/R2 out of sync | Independent SE trimming of mates | Use Trimmomatic paired outputs or fastp/cutadapt paired mode |
## References
Bolger AM, Lohse M, Usadel B. 2014. Trimmomatic: a flexible trimmer for Illumina sequence data. Bioinformatics 30(15):2114-2120.
Chen S, Zhou Y, Chen Y, Gu J. 2018. fastp: an ultra-fast all-in-one FASTQ preprocessor. Bioinformatics 34(17):i884-i890.
MacManes MD. 2014. On the optimal trimming of high-throughput mRNA sequence data. Frontiers in Genetics 5:13.
Del Fabbro C, Scalabrin S, Morgante M, Giorgi FM. 2013. An extensive evaluation of read trimming effects on Illumina NGS data analysis. PLoS ONE 8(12):e85024.
Williams CR, Baccarella A, Parrish JZ, Kim CC. 2016. Trimming of sequence reads alters RNA-Seq gene expression estimates. BMC Bioinformatics 17:103.
Hansen KD, Brenner SE, Dudoit S. 2010. Biases in Illumina transcriptome sequencing caused by random hexamer priming. Nucleic Acids Research 38(12):e131.
## Related Skills
read-qc/adapter-trimming - Remove adapter before quality filtering
read-qc/quality-reports - Read the quality plots that motivate filtering
read-qc/fastp-workflow - All-in-one preprocessing in a single pass
read-alignment/bwa-alignment - Soft-clipping aligner that absorbs low-quality tails
read-alignment/star-alignment - Soft-clipping RNA aligner (light trimming preferred)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!