Skip to content

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

By Bio Help Learning48 min readUpdated FREE

Chapter 1 of 5: Bioinformatics file formats and how your data flows

Every bioinformatics project is a chain of files. The sequencer writes FASTQ. The aligner reads FASTQ and a FASTA reference and writes SAM, BAM or CRAM. The variant caller writes VCF. Genes and exons come as GFF3 or GTF, and regions of interest as BED. If you understand these bioinformatics file formats, you can read any pipeline, check any result by eye, and fix most errors in minutes instead of days.

In this free step-by-step tutorial you will open each format line by line, on small real files that you create or download yourself. You will learn what every column means, which formats count from 0 and which from 1, why .gz is not always the same .gz, and how index files (.fai, .bai, .tbi) make huge files fast. You need only a terminal and the tools from the Conda and Bioconda tutorial.

Chapter 1 video: the file-format map and the 0 vs 1 coordinate trap · 11 min

Choose your reading path

Click a path to choose. With no choice made, the whole page is shown. ▸ Go deeper sections open on click; 🔬 Researcher notes boxes give published evidence, tool defaults and pitfalls. Your choice is remembered on this device.

Chapters:

  1. Bioinformatics file formats and how your data flows
  2. Practice files, FASTA and FASTQ
  3. Alignment formats: SAM, BAM and CRAM
  4. Variants and annotation: VCF, GFF3, GTF and BED
  5. Troubleshooting, practice and next steps
Bioinformatics file formats data flow: sequencer writes FASTQ, aligner uses FASTA reference and writes SAM, BAM or CRAM, variant caller writes VCF or BCF, annotation in GFF3, GTF and BED, coverage in bedGraph and bigWig
Figure 1. How the main bioinformatics file formats connect in a typical sequencing pipeline.

What you will learn

  • Why file formats matter, and the three silent errors they cause (off-by-one, chromosome names, genome build)
  • Text, binary and compressed files: plain gzip vs bgzip, and what index files do
  • The difference between 1-based and 0-based coordinates, with a rule you will never forget
  • FASTA and FASTQ: headers, wrapping, IUPAC codes, quality encoding and the .fai index
  • SAM/BAM/CRAM: the header, the 11 mandatory columns, FLAG bits, CIGAR strings, sorting, indexing and region queries
  • VCF/BCF: meta-lines, the 8 fixed columns, genotypes, indel padding and tabix indexing
  • GFF3, GTF and BED: gene models, the ID/Parent hierarchy, CDS phase, and safe conversion between them
  • How to check, convert and troubleshoot files with samtools, bcftools, bedtools and seqkit

Why bioinformatics file formats matter

A file format is a contract. The tool that writes the file and the tool that reads it agree on what each line and each column means. When both sides follow the contract, pipelines just work. When they do not, you rarely get a crash. You get a wrong answer that looks right.

Three mistakes cause most of these silent errors:

  • Off-by-one coordinates. BED counts from 0, VCF and GFF count from 1. Mix them up and every exon, SNP or primer is shifted by one base.
  • Chromosome names. Ensembl writes 1, UCSC writes chr1. A BED file with chr1 will match nothing in a BAM that uses 1, and many tools just return zero results.
  • Genome build. Position 1,000,000 on GRCh37 (hg19) is a different base from position 1,000,000 on GRCh38 (hg38). The file looks fine; the biology is wrong.

This tutorial teaches you to spot all three by reading the files themselves.

Text, binary, compressed and indexed files

Some formats are plain text: you can open them with less, search them with grep and cut columns with cut. Others are binary: they are smaller and faster but need a tool to read them. Most large text files are also compressed.

FormatStoresText or binaryUsual extensionIndex fileMain tools
FASTASequences (DNA, RNA, protein)Text.fa, .fasta, .fna, .faa.faisamtools faidx, seqkit
FASTQReads + base qualitiesText (usually gzipped).fastq.gz, .fq.gz(rarely)FastQC, seqkit, fastp
SAMRead alignmentsText.samnonesamtools
BAMRead alignmentsBinary (BGZF).bam.bai or .csisamtools, IGV
CRAMRead alignments, reference-compressedBinary.cram.craisamtools
VCFVariants and genotypesText (usually bgzipped).vcf.gz.tbi or .csibcftools, GATK
BCFVariants and genotypesBinary (BGZF).bcf.csibcftools
GFF3 / GTFGene models and featuresText.gff3, .gtf(tabix after sorting)gffread, featureCounts, STAR
BEDGenomic intervalsText.bed(tabix after sorting)bedtools
bedGraph / bigWigSignal along the genome (coverage)Text / binary.bedgraph, .bwbuilt into bigWigdeepTools, IGV, UCSC

Two ideas explain the whole table. BGZF (block gzip, made by bgzip) is gzip cut into small independent blocks, so a tool can jump into the middle of the file. An index is a small side file that says which block holds which genomic region. Together they let IGV or samtools view file.bam chr7:55,000,000-55,300,000 answer in under a second, even for a 100 GB BAM.

▸ Go deeper: why plain gzip cannot be indexed

Normal gzip compresses the file as one long stream. To read byte 5,000,000,000 you must decompress everything before it, because the decompressor’s state depends on all earlier data.

BGZF, defined in the SAM/BAM specification, writes a series of gzip blocks, each holding at most 64 KiB of uncompressed data and each decompressible on its own. A virtual file offset combines two numbers: where the compressed block starts in the file, and how far into the uncompressed block the record starts. An index stores virtual offsets, so a reader seeks straight to the right block and decompresses only that block.

Every BGZF file is still a valid gzip file, so zcat and gunzip read it. The reverse is not true: a file made with plain gzip cannot be indexed by tabix or bcftools index. You will see the exact error in Chapter 5.

Coordinates: 1-based vs 0-based (the rule that saves you)

Every genomic format must say where a base is. There are two systems.

  • 1-based, closed [start, end]: the first base is 1, and both start and end are included. Used by SAM, VCF, GFF3/GTF and by region strings you type, such as chr1:100-200.
  • 0-based, half-open [start, end): the first base is 0, start is included, end is excluded. Used by BED, and inside the binary BAM and BCF files (tools convert for you when they print).
Coordinates in bioinformatics file formats: 1-based closed versus 0-based half-open; the same 15 bases are ref 1 to 15 in GFF3, SAM and VCF, and ref 0 to 15 in BED
Figure 2. The same exon written in both coordinate systems. Only the start number changes.

The rule: to go from 1-based to BED, subtract 1 from the start and keep the end. To go back, add 1 to the start. The end never changes. The length is end − start + 1 in 1-based coordinates and simply end − start in BED.

Worked example. In this tutorial’s practice gene, exon 1 covers bases 1 to 15 of a sequence called ref. In GFF3 that is ref … 1 15. In BED it is ref 0 15. Both describe exactly 15 bases: 15 − 1 + 1 = 15 and 15 − 0 = 15.

▸ Go deeper: why would anyone count from zero?

Half-open intervals make arithmetic clean. The length is end − start. Two intervals touch without overlap when the first’s end equals the second’s start ([0,15) and [15,40)). An empty interval, such as the point where an insertion happens, is simply start = end. Programming languages index arrays from 0, so a BED start can be used directly as a string index: in Python, seq[0:15] returns exactly the first 15 bases.

1-based closed intervals match how biologists talk (“the first base”, “exon 2 spans 1,201–1,500”), which is why human-facing formats such as VCF and GFF use them.

textFree to copy
# Converting coordinates (pseudo-code)
bed_start = one_based_start - 1
bed_end   = one_based_end          # unchanged
length    = bed_end - bed_start    # = one_based_end - one_based_start + 1

# A single 1-based position p (for example a SNP in a VCF) as BED:
bed_line  = chrom, p - 1, p

🔬 Researcher notes: who uses which system

The SAM/BAM specification (section 1.1, “Terminologies and concepts”) states it directly: SAM, VCF, GFF and Wiggle use the 1-based coordinate system; BAM, BCFv2, BED and PSL use the 0-based coordinate system. The UCSC Genome Browser stores BED-style 0-based starts internally but displays 1-based positions, which is why a position copied from the browser into a BED file is often off by one.

Zero-length features follow each format’s own rule. In BED, chromStart = chromEnd marks a point between two bases, such as an insertion site (BED specification v1, 2022). In GFF3, a zero-length feature has start = end and the site is to the right of that base. In VCF, insertions and deletions carry a padding base so that no allele is empty (Chapter 4).

When you report regions in a paper or supplement, say which system you used (for example “coordinates are 1-based, inclusive, GRCh38”). Reviewers and readers cannot guess.

Chromosome names and genome builds

Every file that holds positions also holds sequence names: @SQ SN: lines in SAM, ##contig lines in VCF, the first column of BED and GFF. All files in one analysis must use the same names and the same lengths, taken from the same reference FASTA. Later in this tutorial you will compare names across files with one command.

🔬 Researcher notes: naming conventions and the reference you report

Ensembl and GENCODE GTFs for human use chr1 (GENCODE) or 1 (Ensembl), and the mitochondrial genome is chrM in UCSC-style files but MT in Ensembl files. The SAM specification also allows an M5 tag (MD5 checksum of the sequence) and AS (assembly) on @SQ lines; when present, comparing M5 values is the most reliable way to prove two files used the same reference.

For human data, many pipelines use an “analysis set” FASTA (primary assembly plus, in some sets, the decoy and EBV sequences, with ALT contigs handled specially). Report the exact FASTA file, its source and its release, not just “hg38”.

Quick check: a SNP is at VCF position 1,000. What are its BED start and end?

Start 999, end 1000. Subtract 1 from the start, keep the end. The BED interval [999, 1000) holds exactly one base: the base at 1-based position 1,000.