bedtools — Genomic Interval Analysis Toolkit
Overview
bedtools is the standard toolkit for operating on genomic intervals in BED, BAM, GFF, and VCF formats. It solves the core problem of genome arithmetic: finding overlaps between feature sets, computing coverage, extracting sequences, merging adjacent regions, and annotating features with nearest neighbors. bedtools operates on sorted coordinate lists and runs at C speed, making it practical for whole-genome analyses.
When to Use
- Intersecting ChIP-seq peaks with gene annotations to find promoter-overlapping peaks
- Merging overlapping ATAC-seq peaks or called regions across replicates
- Computing read coverage depth over target capture regions
- Extracting FASTA sequences for motif discovery or primer design
- Finding the nearest gene to each regulatory element or variant
- Subtracting blacklist or repeat regions from peak calls
- Expanding genomic intervals by fixed distance (promoter regions)
- Use
tabixinstead for fast indexed queries of a single genomic region - For normalized coverage bigWig tracks, use
deeptools bamCoverageinstead - Use
mosdepthinstead for whole-genome per-base depth (10× faster)
Prerequisites
- Python packages: None required (command-line only)
- Input requirements: BED/BAM/GFF/VCF files; FASTA reference for
getfasta; genome file (chromosome sizes) forslop/flank/genomecov - Sorting: Most operations require coordinate-sorted input
Check before installing: The tool may already be available in the current environment (e.g., inside a
pixi/condaenv). Runcommand -v bedtoolsfirst and skip the install commands below if it returns a path. When running inside a pixi project, invoke the tool viapixi run bedtoolsrather than barebedtools.
# Bioconda (recommended)
conda install -c bioconda bedtools
# Homebrew (macOS)
brew install bedtools
# Verify
bedtools --version
# bedtools v2.31.0
# Create genome file from FASTA index
samtools faidx reference.fa
cut -f1,2 reference.fa.fai > genome.txt # chr → size table
Quick Start
# Find peaks overlapping genes, then merge overlapping peaks
bedtools intersect -a peaks.bed -b genes.bed -wa -wb > peaks_with_genes.bed
bedtools merge -i peaks.bed > merged_peaks.bed
bedtools coverage -a genes.bed -b reads.bam > gene_coverage.bed
Core API
Module 1: Interval Intersection and Overlap Analysis
Find regions that overlap between two feature sets.
# Basic intersection: output overlapping regions
bedtools intersect -a peaks.bed -b genes.bed
# Report original A and B features for each overlap
bedtools intersect -a peaks.bed -b genes.bed -wa -wb
# Count B overlaps per A feature (adds column)
bedtools intersect -a peaks.bed -b genes.bed -c
# Output: chr1 1000 2000 peak1 gene_count
# Peaks with ANY overlap (report each peak once)
bedtools intersect -a peaks.bed -b genes.bed -u
# Peaks with NO overlap in B (invert filter)
bedtools intersect -a peaks.bed -b blacklist.bed -v
# Require reciprocal 50% overlap both ways
bedtools intersect -a exp1.bed -b exp2.bed -f 0.5 -F 0.5 -r
# Same-strand intersections only
bedtools intersect -a peaks.bed -b genes.bed -s
# Multiple database files with overlap counts per file
bedtools intersect -a query.bed -b enhancers.bed promoters.bed \
-names enh prom -C
# Memory-efficient mode for pre-sorted large files
bedtools intersect -a sorted_peaks.bed -b sorted_genes.bed -sorted
Module 2: Interval Merging and Arithmetic
Combine overlapping intervals and perform set operations.
# Merge overlapping and adjacent intervals
sort -k1,1 -k2,2n peaks.bed | bedtools merge -i stdin
# Merge intervals within 500 bp of each other
bedtools merge -i peaks.bed -d 500
# Merge and count original features
bedtools merge -i peaks.bed -c 1 -o count
# Output: chr1 1000 5000 3 (3 original peaks merged)
# Merge and collapse feature names
bedtools merge -i peaks.bed -c 4 -o collapse -delim ";"
# Output: chr1 1000 5000 peak1;peak2;peak3
# Subtract B from A (remove covered bases)
bedtools subtract -a peaks.bed -b blacklist.bed
# Remove entire A feature if ANY B overlap
bedtools subtract -a peaks.bed -b exclusion.bed -A
# Find genomic gaps (complement of covered regions)
bedtools complement -i merged.bed -g genome.txt
Module 3: Coverage Analysis
Calculate depth and breadth of read coverage over features.
# Coverage stats per feature (count, bases covered, % covered)
bedtools coverage -a target_genes.bed -b aligned.bam
# Output: chr start end gene n_overlapping_reads bases_covered feature_len fraction_covered
# Per-base depth within each feature
bedtools coverage -a targets.bed -b aligned.bam -d
# Output: chr start end name position depth
# Coverage histogram per feature
bedtools coverage -a features.bed -b aligned.bam -hist
# Genome-wide BEDGRAPH (coverage per bin)
bedtools genomecov -ibam aligned.bam -bg -o coverage.bedgraph
# Include zero-coverage regions (for whole-genome coverage)
bedtools genomecov -ibam aligned.bam -bga > full_coverage.bedgraph
# Per-base depth for whole genome
bedtools genomecov -ibam aligned.bam -d > depth.txt
# Scaled BEDGRAPH (RPM normalization: total=50M reads → scale=1/50)
bedtools genomecov -ibam aligned.bam -bg -scale 0.00000002 > rpm.bedgraph
# Strand-specific coverage tracks
bedtools genomecov -ibam rnaseq.bam -bg -strand + > forward.bedgraph
bedtools genomecov -ibam rnaseq.bam -bg -strand - > reverse.bedgraph
Module 4: Sequence Extraction and Nearest Feature
Extract genomic sequences and annotate features with neighbors.
# Extract FASTA sequences for each BED region
bedtools getfasta -fi genome.fa -bed regions.bed -fo sequences.fasta
# Strand-aware extraction (reverse complement - strand)
bedtools getfasta -fi genome.fa -bed regions.bed -s -fo stranded.fasta
# Custom FASTA headers (name + coords)
bedtools getfasta -fi genome.fa -bed peaks.bed -name -fo named.fasta
# Extract and concatenate exons (BED12 spliced transcripts)
bedtools getfasta -fi genome.fa -bed transcripts.bed12 -split -fo exons.fasta
# Find nearest gene to each peak (with distance)
bedtools closest -a peaks.bed -b genes.bed -d
# Output: peak fields... | gene fields... | distance_bp
# Nearest feature on same strand only
bedtools closest -a peaks.bed -b genes.bed -s -d
# Ignore overlapping features (find nearest non-overlapping)
bedtools closest -a peaks.bed -b genes.bed -io -d
# Multiple annotation databases
bedtools closest -a query.bed -b genes.bed enhancers.bed \
-names genes enhancers -d
Module 5: Interval Manipulation
Expand, contract, and shift genomic intervals.
# Expand regions by 500 bp on each side
bedtools slop -i peaks.bed -g genome.txt -b 500
# Asymmetric: 2000 bp upstream, 500 bp downstream of TSS
bedtools slop -i tss.bed -g genome.txt -l 2000 -r 500
# Strand-aware expansion (upstream = 5' side)
bedtools slop -i genes.bed -g genome.txt -l 1000 -r 200 -s
# Create flanking regions (not overlapping the feature)
bedtools flank -i genes.bed -g genome.txt -b 1000
bedtools flank -i genes.bed -g genome.txt -l 2000 -r 0 -s # upstream only
Key Concepts
Coordinate Systems
BED files use 0-based half-open intervals: start is 0-indexed (like Python), end is exclusive. A region chr1:1000-2000 in BED covers bases 1000–1999 (1000 bases).
chr1 1000 2000 peak1 ← covers positions 1000,1001,...,1999
# BED: 0-based start, exclusive end
# VCF: 1-based position (POS)
# GFF: 1-based start and end (both inclusive)
bedtools converts internally — input format is auto-detected. Problems arise when mixing tools with different conventions.
Sorting Requirements
Most bedtools operations require coordinate-sorted input. Pre-sort with:
sort -k1,1 -k2,2n input.bed > sorted.bed
# For large files, use -S 4G for 4 GB sort buffer
sort