FASTQ is the standard file format for storing sequencing reads. Each read is stored as four lines: a header, the sequence, a separator, and a quality string. Understanding this format β€” and what the quality string actually means β€” is the foundation for everything else we do in bioinformatics QC.

πŸ’‘ TL;DR A FASTQ file is a FASTA file with quality scores attached. The quality string encodes the probability of error for each base. Higher quality scores mean fewer sequencing errors.


Anatomy of a FASTQ record

Every read in a FASTQ file looks like this:

@SRR34548621.1 some description here
ACGTTGCAAGCTTGACCGATAGGCTATCGGATCAA
+
IIIIIIIIIIHIIIIIIHII?=;98:7654#%$##

Each record (sequence) will be stored in exactly 4 lines:

  • The header starts with @ and carries the read name and (optionally) metadata. The quality string is always exactly the same length as the sequence β€” one character per base.
  • The sequence line contains the nucleotide sequence of the read.
  • The separator line is always a + and may optionally repeat the header.
  • The quality string encodes the Phred quality score for each base in the sequence.

Phred quality scores

The quality string looks like gibberish, but each character encodes a Phred quality score (Q) β€” a number that tells you how likely that base call is wrong.

The formula is:

Q = βˆ’10 Γ— log₁₀(P) where P = probability the base is wrong

So a base with a 1-in-100 chance of being wrong has Q = 20. A base with a 1-in-1000 chance has Q = 30. The higher the number, the more confident the sequencer was.

Phred score Error probability 1 error in… Accuracy
Q10 10% 10 bases 90%
Q20 1% 100 bases 99%
Q30 0.1% 1,000 bases 99.9%
Q40 0.01% 10,000 bases 99.99%

Q30 is the conventional threshold for β€œgood quality” Illumina data. Q20 is often used as a lower bound for trimming.

How scores are encoded

Each character maps to a Q score:
!
Q0
&
Q5
+
Q10
8
Q23
?
Q30
F
Q37
I
Q40
Red = poor quality β†’ Yellow = acceptable β†’ Green = good quality

Phred scores are stored as single ASCII characters, not as numbers, to keep the file compact. The encoding is:

ASCII character = Phred score + 33

So Q score 30 β†’ 30 + 33 = 63 β†’ the character ?. Score 40 β†’ 73 β†’ I. Score 0 β†’ 33 β†’ !.


Quality expectations: Illumina vs Nanopore

The two platforms have very different error profiles, and that shapes everything about how you work with their data.

Illumina
Typical read: 150 bp
IIIIIIIIIIIIIIIIIIIIIIIFFF??88+
Q:                   40β†’37β†’30β†’23β†’10
  • Short reads (75–300 bp)
  • Per-base accuracy typically Q30–Q40
  • Quality drops toward the 3β€² end (cycle degradation)
  • Random substitution errors (not systematic)
  • Q30 is the standard QC threshold
Oxford Nanopore
Typical read: 5,000–50,000 bp
8+88?88+88&8+?88?+8&88+?88
Q: fluctuates ~Q15–Q25 throughout
  • Long reads (1 kb – 4 Mb)
  • Per-base accuracy typically Q15–Q25 (chemistry-dependent)
  • Errors distributed across the whole read, not just the end
  • Insertion/deletion errors more common than substitutions
  • Q20 is a common threshold for recent chemistries (R10.4.1+)

⚠️ A Nanopore dataset with mean Q12 and an Illumina dataset with mean Q12 are very different problems. Illumina Q12 indicates severe degradation or a failed run. Nanopore Q12 was typical for older flow cells and is still usable for many applications (e.g. species-level metagenomic profiling).

How accuracy has improved in Nanopore

Nanopore accuracy has improved substantially over successive chemistries and basecallers, but still not usually as high as Illumina:

Era Typical Q Notes
R9.4.1 (Guppy, fast mode) Q10–Q14 Useful for long-range structure
R9.4.1 (Guppy, sup mode) Q15–Q18 Most historical datasets
R10.4.1 (Dorado, sup mode) Q20–Q25 Current standard; good enough for variant calling

Inspecting a FASTQ file

You can peek at a FASTQ file directly, but remember that each record is 4 lines β€” so β€œthe first 8 lines” gives you two reads:

zcat sample.fastq.gz | head -8

To count reads:

# Each read = 4 lines
zcat sample.fastq.gz | wc -l | awk '{print $1/4}'

To get a quick summary with seqfu:

seqfu stats sample.fastq.gz
  • Output includes: number of reads, total bases, mean/min/max length, mean quality.

πŸ’‘ seqfu handles gzip-compressed files natively β€” you do not need to decompress first.


Questions

  • ❓ Open a FASTQ file and find the quality string for the first read. What is the Q score of the first base? What is the Q score of the last base? Is there a trend?
  • ❓ A read has a quality string that starts with IIIIIIII and ends with !!!!!!. What does that tell you about how the sequencer performed across the read?
  • ❓ You have a Nanopore dataset with mean Q15 and an Illumina dataset with mean Q30. Which one has more errors per base? By how much?
  • ❓ Why can’t you just use the same QC thresholds for Illumina and Nanopore data?

Previous submodule:
Next submodule: