How to Convert BAM to SAM
By Dr. Zubair Khalid, DVM, MS, PhD ·

By the end of this guide you will be able to turn a valid BAM file into a readable SAM file, inspect the header and alignments, prove that the conversion lost nothing, and convert the SAM back to BAM. You will also know when converting is a poor choice and what to do instead.
You need three things on hand. A working SAMtools installation or another SAM/BAM-aware tool such as Picard or elPrep. Enough free disk space, because SAM text is several times larger than the BAM it came from. And a terminal, because every reliable method here is a command-line method.
What BAM and SAM Actually Are
The SAM/BAM pair is one data model with two encodings. Understanding that sentence removes most of the confusion around conversion.
SAM is tab-delimited text
SAM stands for Sequence Alignment/Map. A SAM file is plain ASCII text organized as tab-separated columns. It has two parts.
The header is a set of lines that begin with @. Each header line type has a meaning. @HD records the file format version and the sort order. @SQ describes one reference sequence and its length. @RG describes a read group, which carries the sample name and sequencing platform. @PG records a program that touched the file, including its command line. @CO holds free-text comments.
The alignment section has one line per read or read pair, with eleven mandatory fields followed by optional tag fields. The mandatory fields are:
- QNAME, the read name.
- FLAG, a bitwise integer that encodes pairing, strand, mapping status, and whether the read is secondary or supplementary.
- RNAME, the reference sequence name.
- POS, the 1-based leftmost mapping position.
- MAPQ, the mapping quality.
- CIGAR, the alignment operation string such as
50Mor10S40M2I8M. - RNEXT, the reference name of the mate or next segment.
- PNEXT, the position of the mate.
- TLEN, the observed template length.
- SEQ, the read sequence.
- QUAL, the per-base quality string in Phred+33 encoding.
Optional fields use a two-letter tag, a type character, and a value, for example NM:i:2 for edit distance or RG:Z:group1 for read group assignment. The SAM specification maintained with the htslib project defines these fields precisely, and samtools enforces them when it parses a file.
BAM is the same data in binary
BAM stands for Binary Alignment/Map. It stores exactly the same header and alignment records, but encoded in a compact binary layout and wrapped in BGZF blocks. BGZF is blocked gzip, a compression scheme that lets a reader jump to a genomic region without decompressing the whole file, provided a separate index file exists.
That index is the .bai file for BAM, or .csi for very large references. The index does not contain alignments. It contains byte offsets that point into the compressed file. This is why you cannot request a region from an unindexed BAM.
Converting BAM to SAM is therefore a decoding operation. The tool decompresses each BGZF block, parses each binary alignment record, and writes the fields back out as tab-separated text. No alignment is recalculated, no read is realigned, and no quality score is changed. The conversion is lossless with respect to alignment content.
Where SAM fits among bioinformatics file formats
New users often mix up FASTQ, FASTA, SAM, BAM, and CRAM. They serve different stages of a sequencing workflow.
FASTQ is the raw read format delivered by most sequencers. Each record occupies four lines: an @ header with the read identifier, the nucleotide sequence, a + separator line, and a quality string of the same length as the sequence. FASTQ carries per-base quality scores, which is its defining feature compared with FASTA.
FASTA is a sequence format with a > header line followed by sequence lines. It has no quality scores and no alignment coordinates. FASTA is used for reference genomes, transcript sequences, and protein sequences. In short, the FASTQ versus FASTA distinction is quality scores and read-level provenance versus plain sequence.
SAM and BAM add the alignment layer. They record where each read maps, how well it maps, and what the aligner decided about pairing. A FASTQ file says "here is a read." A SAM file says "here is a read, and here is where it aligned, with this CIGAR and this mapping quality."
CRAM is a newer reference-based compressed format. It stores reads as differences from a reference sequence and can be considerably smaller than BAM. It is lossy in the sense that the exact BAM byte stream is not recoverable, though the alignment information can be reconstructed given the same reference. CRAM is not a substitute for SAM when you need human-readable text.
Why Convert BAM to SAM
BAM is the working format for most pipelines because it is compact and indexable. SAM is the debugging and interchange format. Common reasons to convert include:
- Inspecting a handful of reads at a locus by eye, without a genome browser.
- Checking header contents such as reference lengths, read groups, and sort order.
- Feeding a tool or script that only accepts text.
- Teaching or learning the alignment data model.
- Archiving a small, human-auditable excerpt alongside a publication or report.
- Diagnosing a pipeline failure where a downstream tool rejects a BAM.
- Writing quick Unix filters with
awk,cut, orgrep.
Conversion is a poor choice when you need random access, when the file is large and you only need a summary, or when a downstream tool accepts BAM directly. Converting a 90 GB human genome BAM to SAM produces a file in the hundreds of gigabytes, and most of that text is never read. Use region queries or summary commands instead.
What You Need Before You Start
The reference implementation is SAMtools, built on the htslib C library. Install it through your package manager, Conda, or a container. Check the version first, because flag names have changed across releases.
samtools --version
Expected output looks like this, with version numbers that vary by installation:
samtools 1.19
Using htslib 1.19
Copyright (C) 2008-2023 [Genome Research](/blog/guides/genome-research) Ltd.
Picard, maintained by the Broad Institute, is a Java alternative. elPrep is a multithreaded Go implementation of SAM/BAM processing that shares the same goals as other SAM/BAM tools and, like them, must manage large in-memory data structures carefully [1]. All three read and write the same format.
You also need disk space. As a working rule, reserve at least five to ten times the BAM size in free space for a full SAM conversion. Compression ratios vary with read length and quality strings, so measure on a small region before committing to a whole-genome job.
Step-by-Step: Convert BAM to SAM
The walkthrough below uses SAMtools because it is the most widely available and the least surprising. Every step shows the command and what success looks like.
Step 1: Confirm the BAM is intact
Do not convert a damaged file. A truncated BAM often decompresses partway and then fails, leaving a partial SAM that looks plausible at the top.
samtools quickcheck -v input.bam
echo $?
quickcheck returns exit code 0 and prints nothing when the file has a valid header and a proper end-of-file marker. The -v flag makes it verbose about failures. A non-zero exit code means the file is incomplete or corrupt, and you should re-download or re-generate it before going further.
Step 2: Inspect the header and count the reads
samtools view -H input.bam
samtools view -c input.bam
-H prints only the header. -c counts alignment records, including secondary and supplementary alignments. Record both numbers. You will compare them against the SAM later.
The header tells you the sort order (SO:coordinate or SO:queryname), the reference names, and the read groups. A header with no @SQ lines is a red flag. It means the BAM was written without reference metadata and many downstream tools will reject it.
Step 3: Run the conversion
samtools view -h -o output.sam input.bam
The single flag that matters most is -h. Without it, SAMtools writes only the alignment lines and drops the entire header. The output is still parseable as a table, but it is not a valid SAM file for most purposes, and converting it back to BAM produces a BAM with no reference dictionary.
If you want to suppress the @PG line that records the conversion command, add -no-PG on a recent SAMtools release:
samtools view -h --no-PG -o output.sam input.bam
The -no-PG flag is useful when you plan to compare headers before and after conversion. Without it, the new @PG line makes the two headers differ by design.
You can also stream to standard output and redirect:
samtools view -h input.bam > output.sam
Both forms are equivalent. The -o form is safer because it fails cleanly if the path is wrong, while a bad redirect can leave an empty file.
Step 4: Check the output immediately
head -n 5 output.sam
samtools view -c output.sam
The head should show @HD and at least one @SQ line before any alignment line. The count from samtools view -c output.sam must equal the count from Step 2. If it does not, the conversion stopped early or you converted a different file.
If you only want a quick peek at alignments without writing a full file, pipe to head:
samtools view -h input.bam | head -n 50
SAMtools may print a broken pipe message when head exits, which is harmless. The first 50 lines are still valid.
Step 5: Convert a subset instead of everything
For large BAMs, extract only what you need. A region query requires an index.
samtools index input.bam
samtools view -h input.bam chr1:1000000-2000000 > region.sam
The region syntax uses the reference name exactly as it appears in the @SQ lines, followed by a colon and a 1-based start and end. If your BAM uses 1 instead of chr1, the query must use 1.
You can also filter by alignment properties. These flags combine:
samtools view -h -q 30 -F 4 -F 0x900 input.bam > filtered.sam
-q 30 keeps reads with mapping quality at least 30. -F 4 excludes unmapped reads. -F 0x900 excludes secondary and supplementary alignments. Remember that repeated -F values are combined into one mask, so this excludes a read if any listed bit is set.
To keep only properly paired reads on a region:
samtools view -h -f 2 input.bam chr1:1000000-2000000 > proper_pair_region.sam
-f requires all listed bits, -F excludes any listed bit. Mixing them up is a common source of confusion.
Step 6: Convert the SAM back to BAM
samtools view -b -o roundtrip.bam output.sam
samtools index roundtrip.bam
The -b flag requests BAM output. The header is preserved because the SAM carries it. Sort order is preserved because conversion never reorders reads.
If your SAM lacks a header, you can still produce a BAM, but the result has no reference dictionary. Add the header back with samtools reheader using a header from the original BAM before you rely on the file.
samtools view -H input.bam > header.sam
samtools reheader header.sam no_header.bam > fixed.bam
Flags and Options That Matter
The table below covers the options you will actually use. Values shown are the ones documented by SAMtools and follow the SAM specification.
| Option | What it does | When to use it |
|---|---|---|
-h | Include the header in SAM output | Always, unless you deliberately want alignments only |
-H | Print only the header | Header inspection and reheadering |
-o FILE | Write to a named file | Preferred over shell redirection |
-b | Output BAM | Round-tripping or re-compressing |
-@ N | Use N additional threads | Large files, BAM output, decompression |
-q INT | Minimum mapping quality | Filtering unreliable alignments |
-f INT | Require all flag bits | Keeping proper pairs (-f 2) or mapped reads (-f 4) |
-F INT | Exclude any listed flag bits | Dropping unmapped (-F 4) or secondary (-F 0x100) |
-s | Sample a fraction of reads | Fast previews with a reproducible seed |
-no-PG | Do not add a @PG line | Byte-level header comparisons |
-O FORMAT | Force output format | Explicit SAM or BAM output on newer releases |
REGION | Restrict to a locus | Requires an index, saves time and disk |
The -@ flag controls threads for compression and decompression. It does not parallelize the text formatting of SAM output in a way that scales linearly, so adding more threads past a few provides diminishing returns for SAM conversion. The elPrep authors describe memory management and multithreading as the central engineering challenges for tools in this class, which is why implementations differ so much in throughput and memory use [1].
Alternative Tools
SAMtools is not the only option. Each alternative has a reason to exist.
Picard SamFormatConverter. The Broad Institute's Picard toolkit includes a dedicated converter.
java -jar picard.jar SamFormatConverter I=input.bam O=output.sam
Newer Picard distributions also expose a picard launcher, so picard SamFormatConverter I=input.bam O=output.sam works in many environments. Picard validates more aggressively than SAMtools and adds @PG lines by default. For strict validation workflows, that extra checking is useful. For pure speed on large files, SAMtools is usually faster.
elPrep. elPrep is an extensible multithreaded framework for processing SAM/BAM files in next-generation sequencing pipelines [1]. Its design targets replacement of multi-step SAMtools and Picard pipelines with a single pass, and its authors compared C++, Go, and Java implementations before choosing Go for the production codebase [1]. For conversion specifically, elPrep has a convert command. Check the syntax for your installed version, because the command set has changed across major releases.
pysam. For Python users, pysam wraps htslib and lets you convert programmatically.
import pysam
with pysam.AlignmentFile("input.bam", "rb") as bam_in:
with pysam.AlignmentFile("output.sam", "w", template=bam_in) as sam_out:
for read in bam_in:
sam_out.write(read)
The template=bam_in argument copies the header. Omitting it produces a SAM without a header, which is the same failure mode as forgetting -h.
htslib directly. The C API in htslib exposes sam_open, sam_hdr_read, and sam_read1. This is the right route if you are writing a compiled tool that must avoid a shell dependency.
biogo/hts. Go developers can use the biogo package, which provides SAM and BAM readers and writers that mirror the htslib data model.
Reading the Output
A typical SAM excerpt looks like this. Tabs separate the fields.
@HD VN:1.6 SO:coordinate
@SQ SN:chr1 LN:248956422
@SQ SN:chr2 LN:242193529
@RG ID:SRR1234567 SM:sample1 PL:ILLUMINA
@PG ID:samtools PN:samtools VN:1.19 CL:samtools view -h -o output.sam input.bam
r001 99 chr1 1001 60 50M = 1051 100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
Read the alignment line left to right. r001 is the read name. 99 is the FLAG. It decodes as 1 (paired) plus 2 (proper pair) plus 32 (mate reverse strand) plus 64 (first in pair), which describes the first read of a forward-strand pair whose mate maps to the reverse strand. chr1 is the reference. 1001 is the leftmost position. 60 is the mapping quality. 50M means 50 aligned bases with no insertions, deletions, or soft clips. = means the mate is on the same reference. 1051 is the mate position. 100 is the template length. The sequence and quality strings are both 50 characters.
Quality characters are Phred+33. The character I has ASCII code 73, which corresponds to a Phred score of 40, so those bases have an estimated error probability of 1 in 10,000. This is the same quality encoding used in FASTQ, which is why FASTQ and SAM quality strings are directly comparable.
Verifying the Conversion Is Correct
Three checks catch almost every problem.
Record count. The alignment count must match.
samtools view -c input.bam
samtools view -c output.sam
Alignment checksum. Because SAMtools reconstructs identical text from both formats, the alignment lines hash identically.
samtools view input.bam | md5sum
samtools view output.sam | md5sum
Both commands print alignment lines without the header, so the hashes should match. If they differ, something changed the data.
Header comparison. With -no-PG on both sides, headers should be identical.
samtools view -H --no-PG input.bam > header_bam.txt
samtools view -H --no-PG output.sam > header_sam.txt
diff header_bam.txt header_sam.txt
An empty diff means the headers match. A difference confined to @PG lines is expected when -no-PG was not used.
A fourth check costs little. Parse the whole SAM to /dev/null. If SAMtools can read every line without a parse error, the file is structurally valid.
samtools view output.sam > /dev/null
Performance, Memory, and Disk
BAM to SAM conversion is a streaming operation. The tool reads one compressed block, decodes it, writes text, and discards it. Memory use stays roughly constant regardless of file size, which is why a laptop can convert a file far larger than its RAM.
Throughput is limited by three things: decompression speed, text formatting, and disk write speed. On a fast local SSD, the disk is rarely the bottleneck. On a network filesystem, it often is.
Threads help decompression but do not turn SAM conversion into a fully parallel operation. The elPrep project's benchmarking work shows that runtime and memory use vary substantially between implementations and languages for the same SAM/BAM workload, so the choice of tool can matter as much as the thread count [1].
Disk is the real constraint. A SAM file contains every base and every quality character as ASCII, plus tab separators and full-length read names. BGZF compression in BAM removes most of that redundancy. Expect a SAM file several times larger than its source BAM, and plan temporary space accordingly. If you only need the file for storage or transfer, write SAM through a compressor:
samtools view -h input.bam | gzip > output.sam.gz
SAMtools and htslib can read a gzipped SAM directly, so this preserves usability while cutting disk use.
Common Mistakes and Limitations
Forgetting -h. The most frequent error by far. The output looks like a SAM file because it has the right number of columns, but the missing header breaks downstream tools and makes the file impossible to convert back cleanly. Always confirm the first lines begin with @.
Editing SAM in Excel or Word. Spreadsheet software reinterprets tab-separated text, converts gene names such as MARCH1 and SEPT2 into dates, strips leading zeros, and silently changes field values. Word adds smart quotes and non-breaking spaces. Use a plain-text editor that preserves tabs, or use awk, cut, or Python for edits. If a SAM file has passed through Excel, treat it as corrupted.
Confusing -f and -F. -f requires bits to be present. -F excludes reads where bits are present. A command written as -f 4 keeps only unmapped reads, which is the opposite of the usual intent. Read the flag before you run it.
Requesting a region without an index. Region queries need a .bai or .csi file next to the BAM. The error is explicit:
[E::idx_find_and_load] Could not retrieve index file for 'input.bam'
Run samtools index input.bam and try again.
Mismatched reference names. Querying chr1 against a BAM that uses 1 produces:
[main_samview] region "chr1:1000-2000" specifies an invalid region or unknown reference
Check samtools view -H input.bam for the exact SN: values before writing a region string.
Missing input file. A typo in the path produces:
[E::hts_open_format] Failed to open file "input.bam" : No such file or directory
Verify with ls -l that the file exists and that you have read permission. Permission problems produce a similar message with "Permission denied" at the end.
Truncated or corrupt BAM. A download that stopped early produces:
[E::bgzf_read_block] Failed to read BGZF block data
The conversion stops at the truncation point and leaves a partial SAM. Delete the partial output, re-download the BAM, and run samtools quickcheck before retrying.
Hand-edited SAM with mismatched fields. Adding or removing bases from SEQ without updating CIGAR and QUAL triggers:
[E::sam_parse1] CIGAR and query sequence are of different length
Fix the edit or regenerate the file from the BAM. Do not patch around the error.
Windows line endings. Files transferred through Windows tools may gain carriage returns. Some parsers tolerate them and some do not. Convert with dos2unix output.sam if a file that looks correct fails to parse.
Assuming conversion sorts or fixes anything. Conversion preserves the existing order and the existing alignments. It will not coordinate-sort a queryname-sorted BAM, will not fix mate information, and will not add missing read groups. Use samtools sort, samtools fixmate, and samtools addreplacerg for those jobs.
Assuming SAM is a long-term archive format. SAM is bulky and slow to parse compared with BAM. For archival storage, keep the BAM or CRAM and generate SAM on demand.
Limitations of interpretation. A SAM file shows you what the aligner produced. It does not tell you whether those alignments are biologically correct. Multimapping reads, paralogous regions, and poorly calibrated mapping qualities are analysis problems, not format problems. If a result will inform a clinical or regulatory decision, follow your laboratory's validated procedures rather than a format conversion alone.
Frequently Asked Questions
Does converting BAM to SAM lose any data?
No alignment data is lost. BAM and SAM encode the same records, and a correct conversion with -h reproduces the header, sequences, qualities, flags, and optional tags. Only the binary compression is removed.
How long does BAM to SAM conversion take?
Time scales with file size and disk speed. A small targeted region finishes in seconds. A whole-genome BAM can take many minutes and produce a file several times larger than the input. Test on a region first to estimate.
Can I convert BAM to SAM without samtools?
Yes. Picard SamFormatConverter, elPrep, pysam, and the htslib C API all perform the same conversion. Any tool that reads the SAM/BAM specification can do it.
Why is my SAM file so much bigger than the BAM?
BAM uses BGZF compression, which removes redundancy from text. SAM stores every base, quality character, and read name as plain ASCII with tab separators. The uncompressed text is naturally several times larger.
Do I need a BAM index to convert to SAM?
No. Converting the entire file does not require an index. You only need a .bai or .csi file when you request a specific region with a syntax like chr1:1000-2000.
How do I convert many BAM files at once?
Use a shell loop. For example, for f in *.bam; do samtools view -h -o "${f%.bam}.sam" "$f"; done. Run samtools quickcheck on each input first so one corrupt file does not leave a partial output.
Can I open a SAM file in Excel?
Do not. Excel converts tab-separated fields, mangles gene names into dates, and strips leading zeros, which corrupts the file silently. Use a plain-text editor, less -S, or a scripting language.
How do I convert SAM back to BAM?
Run samtools view -b -o output.bam input.sam, then samtools index output.bam if you need region access. The SAM must contain a header with @SQ lines for the resulting BAM to be usable.