SAM and BAM Files Explained: FLAGs, CIGAR Strings, and samtools
Decode the 11 SAM columns, bitwise FLAG bits, and CIGAR operations behind every alignment file, then inspect them with samtools view and flagstat.
Every aligner you will ever run — BWA, Bowtie2, HISAT2, STAR, minimap2 — ends its work by writing a SAM file, one line per aligned (or unaligned) read. It looks like an intimidating wall of tab-separated numbers and letters, but it is built from just three ideas: 11 fixed columns, a bitwise FLAG that packs a dozen yes/no facts into one integer, and a CIGAR string that describes how a read lines up against the reference base by base. Once those three ideas click, every alignment file on your disk becomes readable.
What SAM and BAM Actually Are
SAM stands for Sequence Alignment/Map, a plain-text, tab-delimited format defined by the SAM/BAM specification maintained by the HTS-Specs group. It has two parts: a header section, lines starting with @, that records the reference sequences (@SQ), the program that produced the file (@PG), and read-group metadata (@RG); and an alignment section, one line per read, with exactly 11 mandatory tab-separated fields followed by any number of optional tagged fields like NM:i:2 or AS:i:98.
BAM is not a different format — it is the same 11 fields and header, just stored as compressed binary. A raw SAM file for a whole-genome run can reach tens of gigabytes of plain text, so virtually every real pipeline works with BAM instead, and reaches for SAM only when a human needs to eyeball a few lines.
The 11 Mandatory SAM Fields
Every alignment line, whether it came out of BWA, Bowtie2, or STAR, has these columns in this exact order:
| # | Field | Meaning |
|---|---|---|
| 1 | QNAME | Read (query) name, shared by both mates of a pair |
| 2 | FLAG | Bitwise flags describing the alignment (see below) |
| 3 | RNAME | Reference sequence name the read mapped to, e.g. chr7 |
| 4 | POS | 1-based leftmost mapping position on the reference |
| 5 | MAPQ | Mapping quality, Phred-scaled confidence the position is correct |
| 6 | CIGAR | String describing how the read aligns base by base (see below) |
| 7 | RNEXT | Reference name of the mate/next read, = if same as RNAME |
| 8 | PNEXT | Position of the mate/next read |
| 9 | TLEN | Observed template (insert) length, signed |
| 10 | SEQ | The read sequence, or * if not stored |
| 11 | QUAL | Per-base Phred quality string, aligned position-for-position with SEQ |
A MAPQ of 0 means the aligner could not distinguish this position from at least one other equally good spot — genome-wide repeats and duplicated genes routinely produce these. Most variant callers, including GATK4, quietly drop or down-weight reads below a MAPQ threshold for exactly this reason.
Decoding the FLAG Field
The FLAG column is the field most people never learn to read, and it is the one that causes the most silent bugs. It is a single integer, but each of its bits independently answers one true/false question about the read. Instead of eleven extra columns, SAM packs eleven booleans into one number.
| Bit (hex) | Decimal | Meaning |
|---|---|---|
0x1 | 1 | Read is paired |
0x2 | 2 | Read mapped in a proper pair |
0x4 | 4 | Read is unmapped |
0x8 | 8 | Mate is unmapped |
0x10 | 16 | Read aligns to the reverse strand |
0x20 | 32 | Mate aligns to the reverse strand |
0x40 | 64 | Read is the first in the pair |
0x80 | 128 | Read is the second in the pair |
0x100 | 256 | Secondary alignment (not the aligner's primary pick) |
0x200 | 512 | Read fails platform/vendor quality checks |
0x400 | 1024 | PCR or optical duplicate |
0x800 | 2048 | Supplementary alignment (part of a chimeric/split read) |
Three of these matter constantly:
0x4(unmapped) — the aligner could not place this read anywhere. Filtering these out is usually the first thing you do before counting or variant calling.0x10(reverse strand) — theSEQandQUALfields in the record are already reverse-complemented relative to the original read, so this bit tells you which strand of the reference the read matches.0x100(secondary) — for reads with multiple equally good mapping locations, the aligner marks one alignment as primary and the rest as secondary. If you sum reads without excluding secondary and supplementary alignments, you will overcount.
A FLAG value is just the sum of the bits that are set. FLAG=99 decodes as 1 + 2 + 32 + 64, i.e. paired, mapped in a proper pair, mate on the reverse strand, first in pair — a completely ordinary, well-behaved read. You rarely need to do this arithmetic by hand: samtools flags 99 and the online Explain SAM Flags tool both do it for you.
Reading CIGAR Strings
The CIGAR (Compact Idiosyncratic Gapped Alignment Report) string is a compact run-length encoding of how a read's bases line up against the reference, one operation-length pair after another.
| Op | Meaning |
|---|---|
M | Alignment match (can be a sequence match or mismatch — it does not distinguish the two) |
I | Insertion: bases present in the read but absent from the reference |
D | Deletion: bases present in the reference but absent from the read |
N | Skipped region on the reference, e.g. an intron in RNA-seq alignments |
S | Soft clip: bases present in SEQ but excluded from the alignment (e.g. adapter remnants) |
H | Hard clip: bases removed entirely from SEQ, only recorded in the CIGAR |
P | Padding, used for multiple-sequence alignments |
= / X | Exact match / exact mismatch, a more precise alternative to plain M |
Take CIGAR=76M: a 76-base read that aligns cleanly from end to end with no gaps, though individual bases inside that stretch could still be mismatches — M alone does not tell you. Compare that with CIGAR=5S71M: the first 5 bases were soft-clipped (often adapter sequence or low quality), and the remaining 71 bases aligned. In an RNA-seq alignment from a splice-aware aligner like HISAT2 or STAR, you will often see something like CIGAR=50M2000N50M: a 50-base exon, a 2000-base intron the read skips over (N), and another 50-base exon on the far side of the splice junction.
POS plus the CIGAR string is everything a downstream tool needs to reconstruct exactly which reference bases a read covers, which is why so many tools — from coverage calculators to variant callers — parse it directly.
BAM: The Compressed Binary Twin
BAM stores the identical 11 fields and header as SAM, but encodes them in a binary layout and compresses the whole thing with BGZF (Blocked GNU Zip Format) — ordinary gzip, written in independently-decompressible ~64 KB blocks. That block structure is why BAM is useful for more than saving disk space: a .bai or .csi index can point directly at the block containing a given genomic region, so samtools view jumps straight to chr7:140000-141000 in a 30 GB BAM without reading the file from the start. Two practical consequences follow:
- BAM files must be coordinate-sorted before they can be indexed (
samtools sort), because random-access indexing only makes sense against an ordered file. - An index file (
sample.bam.bai) is a separate file that goes stale if the BAM it points to changes; regenerate it withsamtools indexany time you re-sort or re-filter a BAM.
CRAM is a further evolution of the same idea — reference-based compression on top of the BGZF/index model — but BAM remains the format nearly every tool in a standard pipeline, from BWA and Bowtie2 through GATK, expects by default.
Inspecting Files with samtools
samtools is the standard toolkit for all of this, and two subcommands cover most day-to-day inspection.
samtools view converts between SAM and BAM and lets you filter by region or by flag:
# Peek at the header
samtools view -H aligned.bam
# View the first few alignment records as plain text
samtools view aligned.bam | head -3
# Only primary, mapped alignments (drop unmapped, secondary, supplementary)
samtools view -b -F 0x904 aligned.bam > primary_only.bamsamtools flagstat gives you a fast summary of every FLAG bit across the whole file, which is the first sanity check to run on any new BAM:
samtools flagstat aligned.bamYou should see something like:
1200000 + 0 in total (QC-passed reads + QC-failed reads)
0 + 0 secondary
0 + 0 supplementary
0 + 0 duplicates
1188400 + 0 mapped (99.03% : N/A)
1200000 + 0 paired in sequencing
1180200 + 0 properly paired (98.35% : N/A)A healthy Illumina paired-end run typically maps in the high 90s percent and has a properly-paired rate not far behind it. A mapped rate that drops well below 90 percent, or a properly-paired rate far below the mapped rate, is usually the first sign of a reference mismatch, contamination, or a library-prep problem worth investigating before you move on to variant calling or differential expression analysis.
Practical Takeaways
- The 11 SAM fields are fixed and ordered —
QNAME,FLAG,RNAME,POS,MAPQ,CIGAR,RNEXT,PNEXT,TLEN,SEQ,QUAL— memorize the order once and every SAM/BAM line becomes legible. FLAGis bitwise, not enumerated: check individual bits like0x4(unmapped),0x10(reverse strand), and0x100(secondary alignment) rather than treating the raw integer as a category.CIGARdescribes alignment shape, not correctness —Mcovers both matches and mismatches, so pair it with theMDtag or the reference sequence itself when you need to know exactly which bases differ.- BAM is not "compressed SAM" in the naive sense; its BGZF block structure is what makes indexed random access possible, and that index goes stale the moment the underlying file changes.
samtools flagstatshould be the very first command you run on any new alignment file — it turns thousands of individualFLAGvalues into one readable summary in under a second.