Skip to content

Bioinformatics File Formats Explained: FASTA, FASTQ, SAM/BAM, VCF, GTF and BED

By Bio Help Learning48 min readUpdated FREE

Chapter 3 of 5: Alignment formats – SAM, BAM and CRAM

Paid videoThis video is part of the paid study material.Buy the study material or join membership to watchAlready bought or a member? Sign in
Chapter 3 video: SAM, BAM and CRAM, FLAG and CIGAR, sorted indexed BAM · 17 min

SAM, BAM and CRAM: alignment file formats

After alignment, each read gets a position on the reference. SAM (Sequence Alignment/Map) stores this as text. BAM is the same information in compressed binary form, and CRAM compresses further by storing only the differences from the reference (Li et al., 2009; SAM specification). Learn SAM, and you can read all three.

Step 3: Look at the header

A SAM file has a header (lines starting with @) and an alignment section (one line per alignment). Print just the header with -H:

bashCopy disabled · Buy the study material or join membership to copy code
samtools view -H toy.sam
OutputSign in free to see the expected output. No payment needed.Sign in / Create free account

The @SQ lines list every reference sequence with its name (SN) and length (LN). They match toy.fa.fai exactly, which is what you want. The @PG line was added by samtools itself: tools record each program run in the header, so a BAM carries its own history.

Header lineMeaningImportant tags
@HDFile-level information (at most one, first line)VN format version, SO sort order: unknown, unsorted, queryname, coordinate
@SQOne reference sequenceSN name, LN length (both required), M5 MD5, AS assembly
@RGRead group: reads from one library on one laneID, SM sample, LB library, PL platform, PU platform unit
@PGA program that processed the fileID, PN name, VN version, CL command line
@COFree-text comment(none)

Step 4: The 11 mandatory columns

Every alignment line has at least 11 tab-separated columns, always in this order. Optional tags follow from column 12.

bashCopy disabled · Buy the study material or join membership to copy code
samtools view toy.sam | cut -f 1-6 | head -n 6
OutputSign in free to see the expected output. No payment needed.Sign in / Create free account
ColFieldMeaningExample (r001, first line)
1QNAMERead (template) name; mates share itr001
2FLAGBitwise flags: paired, mapped, strand, first/second, …163
3RNAMEReference sequence name (* if unmapped)ref
4POS1-based leftmost position of the alignment7
5MAPQMapping quality: −10 log10 P(position is wrong); 255 = not available30
6CIGARHow the read aligns: matches, insertions, deletions, clips8M4I4M1D3M
7RNEXTMate’s reference (= same as RNAME, * none)=
8PNEXTMate’s position37
9TLENObserved template (fragment) length; + for leftmost mate, − for rightmost39
10SEQRead sequence, on the forward strand of the referenceTTAGATAAAGAGGATACTG
11QUALBase qualities, Phred+33 (* if not stored)*
Anatomy of one SAM alignment line for read r001: QNAME, FLAG 163, RNAME, POS 7, MAPQ 30, CIGAR 8M4I4M1D3M, RNEXT, PNEXT 37, TLEN 39, SEQ, QUAL
Figure 4. One SAM line, column by column, using read r001 from toy.sam.

Note column 10: for reads that aligned to the reverse strand, SAM stores the reverse complement of the read, so that SEQ always matches the forward strand of the reference. The FLAG tells you which reads were flipped.

Step 5: Decode the FLAG

FLAG is a sum of powers of two. Each bit answers one yes/no question. Let samtools decode it:

bashCopy disabled · Buy the study material or join membership to copy code
samtools flags 163
samtools flags 83
samtools flags 4
OutputSign in free to see the expected output. No payment needed.Sign in / Create free account
Bit (decimal)Hexsamtools nameMeaning
10x1PAIREDRead is part of a pair (paired-end sequencing)
20x2PROPER_PAIRBoth mates aligned as the aligner expects
40x4UNMAPThis read is unmapped
80x8MUNMAPThe mate is unmapped
160x10REVERSESEQ is reverse-complemented (read on the − strand)
320x20MREVERSEThe mate is on the − strand
640x40READ1First read of the pair (R1)
1280x80READ2Second read of the pair (R2)
2560x100SECONDARYSecondary (alternative) alignment
5120x200QCFAILFailed platform/vendor quality checks
10240x400DUPPCR or optical duplicate
20480x800SUPPLEMENTARYSupplementary (chimeric/split) alignment

So 163 = 128 + 32 + 2 + 1: paired, properly paired, mate on the reverse strand, and this is R2. Its mate, 83 = 64 + 16 + 2 + 1, is R1 on the reverse strand. Use -f to keep reads that have bits set, and -F to drop reads that have them:

bashCopy disabled · Buy the study material or join membership to copy code
samtools view -c toy.sam
samtools view -c -f 16 toy.sam
samtools view -c -F 0x904 toy.sam
  • -c: count instead of printing.
  • -f 16: only reads on the reverse strand.
  • -F 0x904: drop unmapped (0x4), secondary (0x100) and supplementary (0x800) records, leaving one primary, mapped line per read. This is the usual way to count mapped reads.
OutputSign in free to see the expected output. No payment needed.Sign in / Create free account
▸ Go deeper: testing bits in code

A bit is set when FLAG AND bit is not zero. This works in any language, and in awk you can use integer division and modulo when bitwise operators are missing.

textCopy disabled · Buy the study material or join membership to copy code
# Is a read on the reverse strand? (pseudo-code)
is_reverse = (flag & 16) != 0
is_primary = (flag & 0x900) == 0      # neither secondary nor supplementary
is_mapped  = (flag & 4) == 0

# awk without bitwise operators: bit b is set if int(flag / b) % 2 == 1
awk '!/^@/ && int($2/16)%2==1' toy.sam    # reverse-strand records

The specification requires exactly one primary line per read, the line where FLAG & 0x900 == 0. Counting only primary lines therefore counts each read once.

Step 6: Read a CIGAR string

CIGAR is a list of length + operation pairs. Read r001 has 8M4I4M1D3M: 8 aligned bases, 4 inserted bases, 4 aligned, 1 deleted, 3 aligned.

OpMeaningUses read bases?Uses reference bases?
MAlignment match (base can match or mismatch)yesyes
IInsertion in the read, not in the referenceyesno
DDeletion: reference bases missing from the readnoyes
NSkipped reference region (an intron in RNA-seq)noyes
SSoft clip: bases kept in SEQ but not alignedyesno
HHard clip: bases removed from SEQnono
PPadding (silent deletion from a padded reference)nono
= / XSequence match / mismatch (more specific than M)yesyes
CIGAR 8M4I4M1D3M walked base by base: read r001 aligned to reference positions 7 to 22 with a 4-base insertion after position 14 and a 1-base deletion at position 19
Figure 5. Walking the CIGAR of r001 along the reference. The insertion uses read bases only; the deletion uses reference bases only.

Two sums check any alignment. Read length = sum of M I S = X = 8 + 4 + 4 + 3 = 19, the length of SEQ. Reference span = sum of M D N = X = 8 + 4 + 1 + 3 = 16, so r001 covers reference bases 7 to 22. The spliced read r004 (6M14N1I5M) jumps over 14 reference bases with N, exactly as RNA-seq reads jump over introns.

▸ Go deeper: computing the alignment end and the MD tag
textCopy disabled · Buy the study material or join membership to copy code
# Reference end of an alignment (pseudo-code)
end = POS - 1
for (length, op) in parse(CIGAR):
    if op in 'MDN=X':
        end += length
# end is 1-based and inclusive: r001 -> 7 - 1 + 16 = 22

The optional NM tag is the edit distance to the reference (mismatches + inserted + deleted bases), and MD spells out the mismatching and deleted reference bases. For r001, samtools computes MD:Z:12^G3 and NM:i:5: 12 matching bases, the deleted reference base G, then 3 matches; 4 inserted + 1 deleted = 5 edits. With MD you can rebuild the reference under a read without the FASTA.

🔬 Researcher notes: MAPQ, TLEN and tags are aligner-specific

The specification defines MAPQ as −10 log10 P(mapping position is wrong), but each aligner estimates that probability its own way. BWA-MEM reports 0–60, Bowtie 2 uses a different scale, and STAR uses 255 for unique and 3, 1 or 0 for multi-mapped reads. A MAPQ ≥ 20 or ≥ 30 filter is therefore a convention for one aligner, not a universal threshold: state the aligner and filter together in your Methods.

The specification also notes that there is no clear consensus on how TLEN’s template start and end are defined, so values can differ by a few bases between tools. Use samtools stats insert-size output or Picard’s CollectInsertSizeMetrics rather than raw TLEN when you report fragment sizes.

Standard optional tags are listed in the separate SAMtags specification: for example AS (alignment score), NM (edit distance), MD, NH (number of reported alignments) and RG (read group). Tags starting with X, Y or Z, or with a lowercase letter, are reserved for local use, so their meaning depends on the tool that wrote them.

Step 7: Convert to BAM, sort and index

Almost every downstream tool wants a coordinate-sorted, indexed BAM. One command sorts and writes BAM, another builds the index:

bashCopy disabled · Buy the study material or join membership to copy code
samtools sort -o toy.bam toy.sam
samtools index toy.bam
ls -l toy.sam toy.bam toy.bam.bai
samtools view toy.bam ref:30-40 | cut -f 1-6
  • samtools sort -o toy.bam: sorts by reference and position and writes BAM (the format comes from the .bam name).
  • samtools index: writes toy.bam.bai. The BAM must be coordinate-sorted first.
  • samtools view toy.bam ref:30-40: prints only alignments that overlap bases 30–40 of ref (1-based region). This needs the index.
OutputSign in free to see the expected output. No payment needed.Sign in / Create free account

Notice r004: it starts at 16, but its 14N carries it past position 30, so it overlaps the region. Region queries use the full alignment span, not just POS.

bashCopy disabled · Buy the study material or join membership to copy code
samtools flagstat toy.bam
samtools idxstats toy.bam
Output (first lines of flagstat, then idxstats)Sign in free to see the expected output. No payment needed.Sign in / Create free account

idxstats reads the index and prints, per sequence: name, length, mapped reads and unmapped reads. On a real BAM this gives reads per chromosome in a second, which is a quick sex check (chrY) or contamination check (unexpected contigs).

🔬 Researcher notes: read groups and duplicates

Variant callers and duplicate markers group reads by the @RG header line and the RG:Z: tag on each read. GATK tools such as BaseRecalibrator and HaplotypeCaller require read groups, and the SM tag decides the sample name in the VCF. Add them at alignment (for example bwa mem -R '@RG\tID:lane1\tSM:sample1\tPL:ILLUMINA') or later with samtools addreplacerg. Use one ID per lane and library, so duplicate marking and recalibration work per run.

Duplicate markers (Picard MarkDuplicates, samtools markdup) normally set FLAG bit 0x400 rather than delete reads. Downstream callers skip flagged reads, and samtools flagstat reports them, so the original data stay recoverable. Report the duplicate rate and whether duplicates were marked or removed.

Step 8: CRAM, the smallest alignment format

CRAM stores each read as differences from the reference, so it needs the same reference FASTA to write and to read.

bashCopy disabled · Buy the study material or join membership to copy code
samtools view -C -T toy.fa -o toy.cram toy.bam
samtools index toy.cram
samtools view -T toy.fa toy.cram | head -n 1
  • -C: write CRAM.
  • -T toy.fa: the reference used for compression and decompression.
OutputSign in free to see the expected output. No payment needed.Sign in / Create free account

Our toy CRAM (1,512 bytes) is actually bigger than the BAM (547 bytes), because CRAM has a fixed container overhead. Compression only pays off at real scale. On a simulated set of 100,000 read pairs (150 bp) against a 200 kb genome, we measured:

FileSizevs SAM
SAM (text)84.9 MB1×
BAM23.9 MB3.6× smaller
CRAM 3.1 (lossless)15.6 MB5.4× smaller
For comparison: R1 FASTQ / R1 FASTQ.gz31.6 MB / 14.6 MB

(Your numbers depend on your data.) Real sequencer data, with binned qualities and many identical bases, usually compresses better than our simulation, which used noisy, unbinned qualities.

🔬 Researcher notes: BAI limits, CSI, and keeping CRAM readable

The BAI index divides each reference into bins of 512 Mbp down to 16 kbp, plus a linear index of 16,384 bp windows (SAM specification, section 5). Because of this, BAI cannot index sequences longer than 229 − 1 bases (about 537 Mb). Some plant and amphibian chromosomes are longer; for them use the CSI index (samtools index -c), which supports the full SAM coordinate range.

Every BGZF file should end with a fixed empty “EOF marker” block. Its absence means the file was cut short, for example by a full disk or a failed copy. samtools quickcheck -v *.bam tests the header and the EOF marker of many files in seconds, and should be run before deleting any FASTQ.

CRAM’s reference-based compression (Hsi-Yang Fritz et al., 2011) means a CRAM is only as durable as access to its exact reference. Keep the FASTA with the data, record its MD5s (samtools writes M5 tags into CRAM headers), and note that if a reference cannot be found locally, htslib may try to fetch it by MD5 from the EBI reference server unless you set REF_PATH/REF_CACHE. For long-term archives, many centres (and the EBI) store CRAM.

Methods template: “Reads were aligned to GRCh38 (Ensembl release 115 primary assembly) with <aligner, version>. Alignments were coordinate-sorted and indexed with samtools <version> (Danecek et al., 2021) and stored as CRAM 3.1.”

Quick check: a read has FLAG 99 and CIGAR 5S95M. Is it R1 or R2, which strand, and how many reference bases does it cover?

99 = 64 + 32 + 2 + 1: paired, properly paired, mate reversed, R1, and bit 16 is not set, so the read is on the forward strand. Soft-clipped bases do not use the reference, so it covers 95 reference bases (read length is 100).

Study material

Full access + Certificate

  • Every file of the study material, yours to keep
  • Every chapter, video and solution of this tutorial
  • Copy the code with one click
  • Certificate with QR verification after your project report is approved