Chatomics Field GuideWhat They Don't Teach You

Conversion · BAM → FASTQ

How to Convert BAM to FASTQ (Commands, Checks, and Pitfalls)

The two-step pattern that keeps paired reads paired, plus the default flag that quietly drops reads you didn't know you were missing.

By Ming "Tommy" Tang, Director of Bioinformatics in Big Pharma · Reviewed September 2026 · 3 min read

BAM
.bam, .bai · coordinates: 1-based-closed
FASTQ
.fastq, .fq, .fastq.gz · coordinates: n/a

You convert BAM to FASTQ when you need to hand raw reads back to something that can't take an alignment: remapping to a new reference or aligner, feeding a different pipeline, pulling out a subset of reads (unmapped, a specific region, a single barcode) for reanalysis, or sending sequence data to a collaborator who doesn't want your alignment decisions baked in. It's a step backward through the pipeline, and BAM was never designed to unpack cleanly.

Most of what BAM adds beyond the raw read is fine to lose: MAPQ, CIGAR, NM/MD, alignment position, none of that belongs in a FASTQ anyway. The loss that actually bites is hard-clipped bases. If the aligner hard-clipped part of a read (CIGAR has an 'H'), those bases were permanently deleted from the SEQ field the moment the BAM record was written. No conversion command gets them back. Soft-clipped bases are safe, they're still sitting in SEQ.

The most common way this goes silently wrong is running samtools fastq directly on a coordinate-sorted, indexed BAM. It runs. It produces two files. Nothing errors. But mates for the same read are scattered across the file in genomic-position order instead of sitting next to each other, so read 5000 in R1 and read 5000 in R2 are no longer the same fragment. The aligner you feed this to either fails with a confusing name-mismatch error or, worse, aligns mismatched pairs without complaint. Collate or name-sort first, every time.

The commands

Type your file names once; every command below updates.

  1. 01samtoolsv1.11+

    bash
    samtools collate -u -O sample.bam | samtools fastq -@ 8 -1 sample.fastq_R1.fastq.gz -2 sample.fastq_R2.fastq.gz -0 /dev/null -s /dev/null -n

    collate -u -O streams reads grouped by name (not lexicographically sorted) straight to stdout with no temp BAM written; piping into samtools fastq -@ 8 uses 8 threads and gzip-compresses R1/R2 automatically because of the .gz extension. -0 sends unpaired reads and -s sends singletons (mate missing from this BAM, common after region filtering) to /dev/null instead of mixing them into R1/R2. -n leaves read names untouched instead of appending /1 and /2. This assumes you actually want to discard singletons; route them to a real file if you don't.

  2. 02samtoolsv1.11+

    bash
    samtools sort -n sample.bam -o sample.fastq

    Full name-sort in lexicographic read-name order. Slower and more memory-hungry than collate because it performs a real sort instead of just grouping mates together. Only reach for this when a downstream tool explicitly requires true name-sort order rather than grouped pairs; collate is enough for a straight FASTQ extraction.

  3. 03bedtoolsv2.31.0

    bash
    bedtools bamtofastq -i sample.fastq -fq sample.fastq_R1.fq -fq2 sample.fastq_R2.fq

    Takes the name-sorted BAM produced by the previous command. -fq2 requires the input to be sorted or grouped by read name; feeding it a coordinate-sorted BAM doesn't error, it just pairs the wrong reads together.

  4. 04samtoolsv1.11+

    bash
    samtools fastq sample.bam -F 0 -1 sample.fastq_R1.fastq.gz -2 sample.fastq_R2.fastq.gz -0 /dev/null -s /dev/null -n

    -F 0 overrides the default -F 0x900 filter, which normally drops secondary and supplementary alignments before writing FASTQ. Use this only when you deliberately want split/chimeric alignment records back (for example, re-extracting reads for an SV caller); for a normal remap-from-scratch workflow keep the default filter so you don't get duplicate read names in the output.

Coordinates, strand, names, builds

FASTQ has no coordinate system at all, so this conversion is where genomic position, chromosome naming, and genome build stop mattering rather than where they need reconciling. Strand does carry over, indirectly: if a read was reverse-complemented during alignment (FLAG 0x10), samtools fastq reverses it back to the original sequencer orientation before writing SEQ and QUAL, so the FASTQ reflects how the instrument actually read the fragment, not how it ended up aligned. What's permanently lost: hard-clipped bases (CIGAR 'H') are deleted from SEQ inside the BAM record itself, so no conversion command can recover them, unlike soft-clipped bases which stay in SEQ and come back intact. MAPQ, CIGAR, NM/MD, and mate-mapping-quality (MQ) tags are dropped entirely unless you explicitly preserve them with -T or -i, and barcode/UMI tags only survive correctly on samtools 1.11 or later, since earlier versions had a bug that duplicated the BC:Z tag in the header when both mates carried one.

Check the output before you trust it

  1. 01R1 and R2 have equal read counts

    bash
    echo $(( $(zcat {output}_R1.fastq.gz | wc -l) / 4 )) $(( $(zcat {output}_R2.fastq.gz | wc -l) / 4 ))

    Expected Both numbers are equal integers; a mismatch means one mate stream is missing reads that the other has.

  2. 02Read names line up between mates

    bash
    zcat {output}_R1.fastq.gz | head -1; zcat {output}_R2.fastq.gz | head -1

    Expected The same base read name in both files, ignoring a trailing /1 or /2; if they differ, the BAM was never collated or sorted by name before extraction.

  3. 03FASTQ read total is consistent with the BAM's primary read count

    bash
    samtools view -c -F 0x900 {input}

    Expected Roughly equal to (R1 count + R2 count + singleton count) from the conversion; a large gap usually means secondary/supplementary alignments were unexpectedly included or excluded, or singletons went to /dev/null unnoticed.

  4. 04Sequence and quality strings are the same length in every record

    bash
    zcat {output}_R1.fastq.gz | awk 'NR%4==2{l=length($0)} NR%4==0{if(length($0)!=l) print "mismatch at record", NR}'

    Expected No output; any printed line means a truncated or corrupted FASTQ record.

Errors you will see, and what they mean

No error at all: samtools fastq runs, writes two files, exits 0, and downstream alignment silently produces garbage pairs
Cause: The input BAM was coordinate-sorted (and maybe indexed) but never grouped by read name, so reads sharing a name are scattered across the file instead of adjacent. samtools fastq still emits every record, just in the wrong mate order relative to the second file. Fix: Run samtools collate (or samtools sort -n) on the BAM first, then feed that output into samtools fastq. Never point samtools fastq directly at a coordinate-sorted BAM for paired output.
*****WARNING: Query <file> is neither position nor name sorted (from bedtools bamtofastq)
Cause: bedtools bamtofastq -fq2 checks whether the BAM is name-sorted or grouped and complains when it's still in coordinate order. Fix: Name-sort with samtools sort -n before running bedtools bamtofastq, or skip bedtools and use samtools collate + samtools fastq instead.
Barcode appears twice in the read header, e.g. BC:Z:ACGTACGT-1_BC:Z:ACGTACGT-1
Cause: samtools fastq -i on versions before 1.11 duplicated the BC:Z tag in the FASTQ header when both reads in a pair carried that tag. Fix: Upgrade to samtools 1.11 or later.
R1 and R2 read counts don't match after conversion
Cause: -0 and -s weren't set explicitly, so unpaired or singleton reads landed unpredictably in R1 or R2 instead of a dedicated file, or secondary/supplementary alignments (dropped by the default -F 0x900) ended up present for one mate but not the other. Fix: Always set -0 /dev/null -s /dev/null (or real files) explicitly, and decide deliberately whether you want -F 0 to include secondary/supplementary alignments before comparing counts.
[mem_sam_pe] paired reads have different names (bwa mem, discovered later at realignment)
Cause: The FASTQ pair was extracted from a BAM that wasn't collated or name-sorted first, so R1 and R2 desynced during conversion and the mismatch only surfaces once you try to realign. Fix: Redo the BAM-to-FASTQ conversion with collate or sort -n before fastq extraction, don't try to patch the FASTQ after the fact.

Questions people ask

Do I need to sort or index my BAM before converting it to FASTQ?

You need to collate or name-sort it, not coordinate-sort or index it. Coordinate sorting and indexing exist for tools that query by genomic region; extracting paired FASTQ needs read pairs adjacent in the file, which samtools collate or samtools sort -n provides. Feed samtools fastq a coordinate-sorted BAM and it produces two files with no error, but the mates inside them are out of order.

samtools fastq and bedtools bamtofastq give me different read counts, why?

samtools fastq filters out secondary and supplementary alignments by default (-F 0x900); bedtools bamtofastq doesn't apply the same filter by default. Check the FLAG-based filtering each tool applies before comparing counts, and run samtools view -c -F 0x900 file.bam to see what samtools fastq is actually starting from.

Should I use samtools collate or samtools sort -n before converting?

Use collate for FASTQ extraction: it groups reads sharing a name into contiguous blocks, which is all samtools fastq needs, and it's faster than a true sort because it skips putting names in lexicographic order. Reach for sort -n only when a downstream tool explicitly checks for real name-sort order, which some bedtools bamtofastq usage patterns do.

Can I get my exact original FASTQ back from a BAM?

Only if nothing was hard-clipped. Soft-clipped bases stay in the SEQ field and come back fine; hard-clipped bases (CIGAR 'H') were deleted from the record during alignment and are gone for good. You'll also be missing any read that never made it into the BAM, such as reads removed by trimming or QC before alignment ever happened.

What does the -n flag do in samtools fastq?

It leaves read names as-is instead of appending /1 and /2 mate suffixes. Flag behavior around -n has shifted across samtools releases, including interactions with CRAM reference decoding, so check the man page for your installed version before assuming it does exactly one thing.

Related reading on the blog

Sources

  1. bedtools bamtofastq documentation — source for the name-sort/grouping requirement behind -fq2
  2. samtools GitHub: Releases and changelog — source for the 1.11 fix to the duplicated BC:Z barcode bug
  3. samtools GitHub: Issues tracking collate and fastq behavior — source for collate vs sort -n behavior and the default -F 0x900 filter in samtools fastq
  4. Fastq-pair: efficient synchronization of paired-end fastq files — source for why paired FASTQ files must keep matching read counts and order