How to Trim RNA-seq Reads
By the end of this guide you will have a set of trimmed paired-end FASTQ files, a JSON quality report for each sample, and enough evidence to say whether trimming helped, did nothing, or hurt. You need the raw FASTQs (gzipped, R1 and R2), knowledge of the library prep kit and sequencer, roughly 2× the raw data volume in free disk, and four tools: fastqc, fastp, multiqc, and whichever aligner or quantifier you plan to use downstream (STAR, salmon, or kallisto). Everything here assumes Illumina short reads, which is what almost all bulk RNA-seq is. All of it installs cleanly with conda install -c bioconda fastqc fastp multiqc cutadapt seqkit.
A word on why this step exists at all. Illumina sequencing works by ligating synthetic adapter sequences to both ends of each cDNA fragment. Those adapters carry the P5/P7 flow-cell binding sites, the index barcode, and the sequencing primer binding site, and together they add roughly 58 to 66 bases to each end of the fragment. The sequencer starts reading immediately after the primer, so under normal circumstances you never see adapter in your data. You see it when the insert is shorter than the read length: a 200 bp read on a 120 bp fragment runs off the end of the insert and into the adapter on the far side. The portion that reads through is the TruSeq stem, AGATCGGAAGAGCACACGTCTGAACTCCAGTCA on read 1 and AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT on read 2, 33 bases each. Nextera and Illumina DNA Prep libraries instead show CTGTCTCTTATACACATCT. Published RNA-seq pipelines almost universally include an adapter and quality trimming step before alignment or assembly 12.
1. Look at the raw data before you touch it
Trimming decisions follow from what is in the files, so start by measuring. Two commands get you most of the way.
mkdir -p qc/raw logs trim
seqkit stats -a raw/*.fastq.gz
fastqc -t 8 -o qc/raw raw/*.fastq.gz
multiqc -o qc/raw qc/raw
seqkit stats -a gives you read counts, minimum, average and maximum read length, and N50. If average length equals maximum length exactly, no trimming has been applied upstream by the sequencing provider. If it is a few bases lower, someone already ran something and you should find out what before running it again.
In the FastQC report, three modules matter here. The Adapter Content plot tells you what fraction of reads carry adapter and at what cycle it starts accumulating. Per Base Sequence Quality tells you whether quality collapses at the 3’ end, which is common on older chemistry and rare on patterned-flow-cell instruments. Overrepresented Sequences will name the adapter outright if it is abundant. Ignore the Per Base Sequence Content failure at cycles 1 to 12: that is the random hexamer priming bias intrinsic to most RNA-seq protocols, and trimming those bases off does more harm than good.
2. Identify the chemistry, not just the adapter
Three properties of the library change what you should do, and none of them are visible from the FASTQ alone.
The kit determines the adapter. TruSeq-style stranded mRNA and Ribo-Zero kits use the sequence above. Nextera-based and some Watchmaker or NEB kits use different stems. If nobody can tell you, fastp --detect_adapter_for_pe infers it from overlapping read pairs, which works well when insert sizes are short enough for R1 and R2 to overlap.
The instrument determines the poly-G problem. NextSeq, NovaSeq, and NovaSeq X use two-color chemistry, where “no signal” is called as G. When a cluster stops producing signal, the instrument emits a long run of high-quality G bases at the 3’ end. These are not real sequence, they align nowhere, and standard quality trimming will not remove them because their Q scores look fine. You must handle them explicitly.
The protocol determines whether there are UMIs and whether poly-A tails end up in the reads. Unique molecular identifiers are short random barcodes, typically 8 to 12 bases, sitting at the start of read 1 or read 2 or in a separate index read. They must be moved into the read name before any other trimming, or you lose them. Three-prime tag libraries such as QuantSeq deliberately sequence into the poly-A tail and need poly-X trimming.
3. Decide how aggressive to be
Our default position: trim adapters and poly-G always, trim quality gently or not at all, and never hard-trim to a fixed length. The reason is that modern aligners soft-clip. STAR and HISAT2 will locally align the informative part of a read and clip the rest, and salmon’s selective alignment does something similar. For a read with 15 bases of adapter at the 3’ end, the aligner usually recovers the correct placement on its own. Aggressive quality trimming, by contrast, shortens reads systematically and can shift which isoform a read is compatible with, which propagates into transcript-level quantification.
There is one case where adapter trimming is not optional: short inserts. Degraded RNA, FFPE material, and over-fragmented libraries produce inserts of 50 to 100 bp, and with 150 bp reads that means half of every read is adapter. Soft-clipping handles a little adapter well and a lot of adapter badly, and the same reads also become dimer-like fragments that inflate duplicate rates. Trim those properly.
The other case is de novo assembly. Assemblers do not soft-clip. Adapter bases become chimeric k-mers, and the assembly graph fills with spurious branches. Studies that assemble transcriptomes without a reference trim before assembly for exactly this reason 1.
4. Run fastp as the default
fastp is what we reach for first: it does adapter detection, quality trimming, poly-G and poly-X trimming, length filtering, UMI extraction, and QC reporting in one multithreaded pass, and it emits a machine-readable JSON you can aggregate later.
SAMPLE=S01
fastp \
-i raw/${SAMPLE}_R1.fastq.gz -I raw/${SAMPLE}_R2.fastq.gz \
-o trim/${SAMPLE}_R1.fastq.gz -O trim/${SAMPLE}_R2.fastq.gz \
--detect_adapter_for_pe \
--adapter_sequence AGATCGGAAGAGCACACGTCTGAACTCCAGTCA \
--adapter_sequence_r2 AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT \
--trim_poly_g --poly_g_min_len 10 \
--cut_tail --cut_tail_window_size 4 --cut_tail_mean_quality 20 \
--length_required 36 \
--qualified_quality_phred 15 --unqualified_percent_limit 40 \
--thread 8 \
--json qc/${SAMPLE}.fastp.json --html qc/${SAMPLE}.fastp.html \
2> logs/${SAMPLE}.fastp.log
What each choice does. --detect_adapter_for_pe infers adapters from read-pair overlap and combines with the sequences you supply, so specifying both is belt and braces rather than redundant. --trim_poly_g is on by default when fastp detects a NextSeq or NovaSeq instrument in the read header, but instrument detection fails on renamed files, so set it explicitly. --cut_tail runs a sliding window from the 3’ end and stops at the first window averaging Q20 or better; it is the gentler cousin of Trimmomatic’s SLIDINGWINDOW. Note that --cut_front is available too, and we leave it off, because 5’ bases in RNA-seq are usually fine and cutting them increases mapping ambiguity at exon starts.
--length_required 36 discards read pairs where either mate falls below 36 bases. Below roughly 30 bases, a read maps to too many places in the transcriptome to be informative, and short reads drag down the unique mapping rate. Raise it to 50 if you have 150 bp reads and plenty of depth.
Deliberately absent: any --trim_front1 or --max_len1. Fixed trimming throws away good bases from every read to fix a problem present in a minority.
5. Handle UMIs and poly-A when the protocol requires it
If your library carries inline UMIs, extract them first, in the same fastp invocation, before adapters are removed:
fastp -i raw/R1.fq.gz -I raw/R2.fq.gz -o trim/R1.fq.gz -O trim/R2.fq.gz \
--umi --umi_loc=read1 --umi_len=8 --umi_skip=2 \
--detect_adapter_for_pe --trim_poly_g --length_required 36 \
--json qc/umi.json --html qc/umi.html
--umi_skip=2 drops the spacer bases that some kits place between the UMI and the insert. fastp appends the UMI to the read name, where umi_tools dedup or gencore can find it after alignment. If your UMI scheme is more complicated, for instance split across both reads, use umi_tools extract --bc-pattern=NNNNNNNN --bc-pattern2=NNNNNNNN upstream and run fastp afterwards with UMI handling disabled.
For 3’ tag counting libraries, or for any library where FastQC shows a spike in A-homopolymer content, add --trim_poly_x --poly_x_min_len 10. Poly-X trimming runs after adapter removal and catches poly-A tails that the adapter search missed. Leave it off for standard full-length mRNA libraries, where a genuine internal A-rich stretch at a read end would be discarded for no reason.
6. Verify the trim improved something
This is the step people skip, and it is the one that catches mistakes. Compare before and after on four numbers.
fastqc -t 8 -o qc/trimmed trim/*.fastq.gz
multiqc -o qc/final qc/raw qc/trimmed qc/*.fastp.json
Look at: the fraction of reads surviving (should be above 90 percent for a healthy library; below 80 percent means your filters are too strict or the library is degraded), adapter content in the trimmed FastQC (should be flat at zero), the read length distribution (a large spike at exactly --length_required means many inserts were shorter than the read length), and duplicate rate.
Then run the aligner on both versions of one sample and compare. With STAR, the relevant fields in Log.final.out are “Uniquely mapped reads %” and ”% of reads unmapped: too short”. If trimming moved unique mapping by less than half a percentage point, trimming was cosmetic for this dataset, which is the common outcome for high-quality libraries with long inserts. If ”% of reads unmapped: too short” dropped by several points, the adapters were genuinely interfering.
STAR --genomeDir idx --readFilesIn trim/S01_R1.fastq.gz trim/S01_R2.fastq.gz \
--readFilesCommand zcat --runThreadN 12 \
--outFileNamePrefix bam/S01. --outSAMtype BAM SortedByCoordinate
grep -E "Uniquely mapped reads %|too short" bam/S01.Log.final.out
For salmon, the equivalent check is the mapping rate in aux_info/meta_info.json. Anything above 75 percent for a well-annotated human or mouse transcriptome is normal.
7. Choose a different tool when fastp does not fit
cutadapt is the precise instrument. It gives you explicit control over error rate, minimum overlap, and anchored adapters, and it is the right choice when you need a non-standard adapter, a 5’ adapter, or linked adapters (small RNA libraries, for example).
cutadapt -j 8 \
-a AGATCGGAAGAGCACACGTCTGAACTCCAGTCA \
-A AGATCGGAAGAGCGTCGTGTAGGGAAAGAGTGT \
--nextseq-trim=20 -q 20 -O 3 -e 0.1 -m 36 --pair-filter=any \
-o trim/R1.fq.gz -p trim/R2.fq.gz \
raw/R1.fq.gz raw/R2.fq.gz > logs/cutadapt.log
--nextseq-trim=20 is cutadapt’s poly-G solution: it runs quality trimming while treating G as low quality regardless of its reported score. -O 3 sets the minimum adapter overlap; the default of 3 means about 1 in 64 reads gets a base trimmed by chance, which is harmless but visible in the length distribution. Raise it to 5 if that bothers you.
Trimmomatic answers the question people ask most often: what is it for. It is a Java tool that performs adapter clipping and quality trimming in one pass over the reads, using a palindrome mode that detects adapter read-through by comparing the two mates of a pair against each other. It predates fastp, is slower, and is single-purpose, but it remains correct and widely used, and a large fraction of published pipelines rely on it 34.
trimmomatic PE -threads 8 -phred33 \
raw/R1.fq.gz raw/R2.fq.gz \
trim/R1.paired.fq.gz trim/R1.unpaired.fq.gz \
trim/R2.paired.fq.gz trim/R2.unpaired.fq.gz \
ILLUMINACLIP:TruSeq3-PE-2.fa:2:30:10:2:True \
LEADING:3 TRAILING:3 SLIDINGWINDOW:4:20 MINLEN:36
The final two arguments to ILLUMINACLIP matter and are often omitted: 2 is the minimum adapter length for palindrome-mode clipping, and True keeps both reads of a pair rather than discarding the reverse read as a duplicate. Without True you silently halve your paired output on short-insert libraries. Trimmomatic has no poly-G handling, so it is the wrong default for NovaSeq data.
bbduk.sh from BBTools is the fastest option on very large files and has the best k-mer-based adapter matching, using ktrim=r k=23 mink=11 hdist=1 tbo tpe. It is the one we use when a library has multiple adapter variants and we want a single reference FASTA to cover all of them.
8. Record what you did
Trimming parameters are part of the analysis, and changing them changes results. Save the exact command, the tool version (fastp --version, cutadapt --version), and the JSON report next to the trimmed files. If you are processing more than a handful of samples, use nf-core/rnaseq, which wraps fastp or Trim Galore behind versioned containers and produces a MultiQC report covering every stage. Multi-omics studies that integrate RNA with proteomic or methylation layers depend on this kind of provenance, because a quantification difference traced back to an undocumented trimming change is difficult to unwind after the fact 56.
Common problems
Survival rate below 70 percent. Usually --length_required is too high for the insert size distribution, or the library is degraded and most fragments are genuinely shorter than the read length. Check the fastp JSON field read1_after_filtering.total_reads against filtering_result.too_short_reads. Lower the threshold to 25 or 30 and re-check unique mapping rate rather than assuming the reads are junk.
Adapter content persists after trimming. Either the adapter sequence is wrong for the kit, or the adapter appears at the 5’ end (fastp only trims 3’ adapters by default). Pull 100,000 reads and grep for candidate stems: zcat raw/R1.fq.gz | head -400000 | grep -c AGATCGGAAGAGC and the same for CTGTCTCTTATACACATCT.
Long runs of G at the 3’ end of trimmed reads. Poly-G trimming was off. fastp enables it only when it recognises the instrument from the read header, so pass --trim_poly_g explicitly, or use cutadapt --nextseq-trim.
Mapping rate fell after trimming. Almost always over-aggressive quality trimming. Drop --cut_tail entirely, or lower the threshold from Q20 to Q15, and re-run. The reads that quality trimming shortens are frequently still mappable in full because aligners tolerate mismatches better than they tolerate missing bases.
Paired files out of sync. The aligner will complain about unequal read counts or mismatched names. This happens when R1 and R2 are trimmed in separate single-end runs. Always pass both mates to one invocation, and if you must recover, use seqkit pair -1 R1.fq.gz -2 R2.fq.gz.
UMIs vanished. The UMI bases were trimmed as part of the insert because extraction ran after adapter trimming. Re-run from the raw files with extraction first.
Wondering whether depth is the real issue. Adapter trimming does not rescue an underpowered experiment. For differential expression on protein-coding genes in a well-annotated genome, 20 to 30 million reads per sample is the usual target, and isoform-level or novel-transcript work typically calls for 50 to 100 million. Replicate number generally buys more statistical power than depth beyond that point.
Interpreting expression changes clinically. Trimming and quantification are measurement. Any inference about health from a transcript’s abundance belongs with a qualified clinician who can see the full picture, particularly for immune or inflammatory signatures where expression shifts with time of day, recent infection, and medication 2.
Oak builds longitudinal molecular profiles of individuals: whole-genome sequencing, RNA sequencing, proteomics, blood biomarkers, and continuous glucose data, integrated into one model of you. Build your profile.
Footnotes
-
Rosa Maria Sepe, Ida Orefice, Marco Di Marsico, et al. Coding and non-coding RNA sequencing during Thalassiosira gravida resting cell formation. Scientific Data, 2026. https://doi.org/10.1038/s41597-026-06744-z ↩ ↩2
-
Sarah K. Sasse, Vineela Kadiyala, Min Chen, et al. Multi-omics analysis of glucocorticoid receptor crosstalk with Type I and Type II inflammatory signaling in human airway smooth muscle cells. American Journal of Physiology-Lung Cellular and Molecular Physiology, 2026. https://doi.org/10.1152/ajplung.00281.2025 ↩ ↩2
-
Xinxin Zhang, Jiajun Feng, Zeng Wang, et al. Multi-omics links short-term epigenetic plasticity to long-term genetic adaptation to heat stress in a montane tree species. Plant Communications, 2026. https://doi.org/10.1016/j.xplc.2026.102073 ↩
-
Sivakumar Swaminathan, Youngwoo Lee, Corrinne E. Grover, et al. Comparative multi “omics” profiling of Gossypium hirsutum and Gossypium barbadense fibers at high temporal resolution reveals key differences in polysaccharide composition and associated glycosyltransferases. Frontiers in Plant Science, 2026. https://doi.org/10.3389/fpls.2026.1639424 ↩
-
Mario Gorenjak, Mateja Zupin, Gregor Jezernik, et al. Omics data integration identifies ELOVL7 and MMD gene regions as novel loci for adalimumab response in patients with Crohn’s disease. Scientific Reports, 2021. https://doi.org/10.1038/s41598-021-84909-z ↩
-
Carolina Oliveira-Rizzo, Camilla L. Colantuono, Ana J. Fernández-Alvarez, et al. Multi-Omics Study Reveals Nc886/vtRNA2-1 as a Positive Regulator of Prostate Cancer Cell Immunity. Journal of Proteome Research, 2024. https://doi.org/10.1021/acs.jproteome.4c00521 ↩