minimap2-pure-rs
August 1, 2026 · View on GitHub
A pure Rust reimplementation of minimap2 v2.31 (commit 3c28777e7e2dcc90f825de1b9f17a89cca7d4452), the versatile sequence alignment program for long and short reads.
Anyone interested in a pure-Rust aligner should have a look at rammap / github. The ambition of rammap goes beyond this crate, which merely aims to be a faithful translation of minimap2.
- 2026-08-01: CI added
- 2026-06-01: Perf-guided RMQ chaining optimization. The translation now tracks version 2.31. Current local hg38/HiFi benchmark numbers are in the performance section; this build is faster than C minimap2 on that run.
- 2026-05-15: This code is now ready to be tested on real data, but stay vigilant to possible bugs. About 10-20% faster than original code on a large genome, possibly faster on smaller genomes.
This is an LLM-mediated faithful (hopefully) translation, not the original code!
Most users should probably first see if the existing original code works for them, unless they have reason otherwise. The original source may have newer features and it has had more love in terms of fixing bugs. In fact, we aim to replicate bugs if they are present, for the sake of reproducibility! (but then we might have added a few more in the process)
There are however cases when you might prefer this Rust version. We generally agree with this manifesto but more specifically:
- We have had many issues with ensuring that our software works using existing containers (Docker, PodMan, Singularity). One size does not fit all and it eats our resources trying to keep up with every way of delivering software
- Common package managers do not work well. It was great when we had a few Linux distributions with stable procedures, but now there are just too many ecosystems (Homebrew, Conda). Conda has an NP-complete resolver which does not scale. Homebrew is only so-stable. And our dependencies in Python still break. These can no longer be considered professional serious options. Meanwhile, Cargo enables multiple versions of packages to be available, even within the same program(!)
- The future is the web. We deploy software in the web browser, and until now that has meant Javascript. This is a language where even the == operator is broken. Typescript is one step up, but a game changer is the ability to compile Rust code into webassembly, enabling performance and sharing of code with the backend. Translating code to Rust enables new ways of deployment and running code in the browser has especial benefits for science - researchers do not have deep pockets to run servers, so pushing compute to the user enables deployment that otherwise would be impossible
- Old CLI-based utilities are bad for the environment(!). A large amount of compute resources are spent creating and communicating via small files, which we can bypass by using code as libraries. Even better, we can avoid frequent reloading of databases by hoisting this stage, with up to 100x speedups in some cases. Less compute means faster compute and less electricity wasted
- LLM-mediated translations may actually be safer to use than the original code. This article shows that running the same code on different operating systems can give somewhat different answers. This is a gap that Rust+Cargo can reduce. Typesafe interfaces also reduce coding mistakes and error handling, as opposed to typical command-line scripting
But:
- This approach should still be considered experimental. The LLM technology is immature and has sharp corners. But there are opportunities to reap, and the genie is not going back into the bottle. This translation is as much aimed to learn how to improve the technology and get feedback on the results.
- Translations are not endorsed by the original authors unless otherwise noted. Do not send bug reports to the original developers. Use our Github issues page instead.
- Check the original Github pages for information about the package. This README is kept sparse on purpose. It is not meant to be the primary source of information
- If you are the author of the original code and wish to move to Rust, you can obtain ownership of this repository and crate. Until then, our commitment is to offer an as-faithful-as-possible translation of a snapshot of your code. If we find serious bugs, we will report them to you. Otherwise we will just replicate them, to ensure comparability across studies that claim to use package XYZ v.666. Think of this like a fancy Ubuntu .deb-package of your software - that is how we treat it
This blurb might be out of date. Go to this page for the latest information and further information about how we approach translation
Installation
cargo install --path .
Or build from source:
cargo build --release
# Binary at ./target/release/minimap2-pure-rs
Usage
Basic mapping (PAF output)
minimap2-pure-rs ref.fa query.fq
With CIGAR string
minimap2-pure-rs -c ref.fa query.fq
SAM output
minimap2-pure-rs -a ref.fa query.fq | samtools sort -o aligned.bam
Paired-end short reads
minimap2-pure-rs -ax sr ref.fa read1.fq read2.fq
Using presets
minimap2-pure-rs -x map-ont ref.fa ont_reads.fq # Oxford Nanopore
minimap2-pure-rs -x map-pb ref.fa pb_reads.fq # PacBio CLR
minimap2-pure-rs -x map-hifi ref.fa hifi_reads.fq # PacBio HiFi
minimap2-pure-rs -x sr ref.fa reads.fq # Short reads
minimap2-pure-rs -x asm5 ref.fa assembly.fa # Assembly-to-reference
minimap2-pure-rs -x splice ref.fa rna_reads.fq # RNA/splice-aware mapping
Index management
# Build and save index
minimap2-pure-rs -d ref.mmi ref.fa
# Map using prebuilt index
minimap2-pure-rs ref.mmi query.fq
When --alt is provided while dumping an index, Rust-written .mmi files
persist ALT contig flags and restore them when loaded by this crate.
Options
Usage: minimap2-pure-rs [OPTIONS] <TARGET> [QUERY]...
Arguments:
<TARGET> Reference FASTA/index file
[QUERY]... Query FASTA/FASTQ file(s)
Options:
-x, --preset <PRESET> Preset (map-ont, map-pb, map-hifi, sr, splice, asm5, asm10, asm20, ...)
-k <KMER> k-mer size [default: from preset]
-w <WINDOW> Minimizer window size [default: from preset]
-t, --threads <THREADS> Number of threads [default: 3]
-a, --sam Output SAM
-c Output CIGAR in PAF
--cs Output cs tag
--ds Output ds tag
--MD Output MD tag
--eqx Use =/X instead of M in CIGAR
-A <MATCH_SCORE> Matching score
-B <MISMATCH> Mismatch penalty
-f <FLOAT> Filter top fraction of repetitive minimizers
-O <INT[,INT]> Gap open penalty [,second]
-E <INT[,INT]> Gap extension penalty [,second]
-r <INT[,INT]> Bandwidth [,long]
-F <MAX_FRAG_LEN> Max fragment length
-N <BEST_N> Top N secondary alignments
--secondary <yes|no> Output secondary alignments
-s <MIN_DP_SCORE> Min alignment score
-Q Do not output base qualities in SAM
--sam-hit-only Only output SAM records with hits
--secondary-seq Output SEQ/QUAL for secondary alignments with hard clipping
--paf-no-hit Output unmapped in PAF
-d <FILE> Dump index to file
-Y Soft clipping
-L Long CIGAR in CG tag for BAM compatibility
-R <STR> Read group line
-H HPC mode (homopolymer compression)
-P Output all chains
--for-only Only map to forward strand
--rev-only Only map to reverse strand
--qstrand Preserve query-strand coordinates for reverse-strand PAF output
--copy-comment Copy FASTA/FASTQ comments to output
--idx-no-seq Build an index without target sequences
--junc-bed <FILE> BED12 splice junction annotations
--write-junc Emit junction lines from spliced alignments
--junc-bonus <INT> Splice junction score bonus
--junc-pen <INT> Splice junction penalty
-J <INT> Splice model selector (0 old, 1 new)
-u <CHAR> Splice strand mode (f, r, b, n)
--alt <FILE> ALT contig name list
--alt-drop <FLOAT> ALT contig score drop fraction
--split-prefix <PFX> Split-index mapping and merge
-G <MAX_INTRON> Max intron length (splice mode)
-T, --sdust-thres <INT> SDUST threshold (0 to disable)
-K <NUM> Mini-batch size for mapping
-I <NUM> Split index for every NUM input bases
-h, --help Print help
-V, --version Print version
Output formats
PAF (default)
Tab-separated format with 12 mandatory fields plus optional tags:
query qlen qs qe strand target tlen rs re mlen blen mapq [tags]
Tags include: tp (type), cm (minimizer count), s1/s2 (chain scores),
NM (edit distance), ms (max DP score), AS (alignment score),
de/dv (divergence), cg (CIGAR), cs (cs tag), rl (repeat length).
SAM (-a)
Standard SAM format compatible with samtools and downstream tools.
Includes CIGAR, clipping (hard by default, soft with -Y), and alignment tags.
Library API
Use minimap2-pure-rs as a Rust library:
use minimap2::aligner::Aligner;
// Build aligner with preset
let aligner = Aligner::builder()
.preset("map-ont")
.index("ref.fa")
.with_cigar()
.build()
.unwrap();
// Map a sequence
let hits = aligner.map(b"ACGTACGT...");
for hit in &hits {
let name = aligner.seq_name(hit.rid as usize);
println!("{name}:{}-{} strand={} mapq={}",
hit.rs, hit.re,
if hit.rev { '-' } else { '+' },
hit.mapq);
}
Or use the lower-level API:
use minimap2::prelude::*;
let (io, mut mo) = preset("map-hifi").unwrap();
let mi = MmIdx::build_from_file("ref.fa", io.w as i32, io.k as i32,
io.bucket_bits, io.flag, io.mini_batch_size, io.batch_size).unwrap().unwrap();
mapopt_update(&mut mo, &mi);
let result = map_query(&mi, &mo, "read1", b"ACGT...");
Architecture
src/
lib.rs Public API + prelude
aligner.rs High-level Aligner builder API
main.rs CLI (clap)
types.rs Core data types (Mm128, AlignReg, Cigar, ...)
flags.rs Bitflags (MapFlags, IdxFlags, KswFlags)
options.rs Presets and option validation
seq.rs DNA encoding, complement, 4-bit packing
sort.rs Radix sort for Mm128/u64
sketch.rs Minimizer extraction (hash64, HPC)
sdust.rs Low-complexity masking
bseq.rs FASTA/FASTQ I/O (gzip support)
seed.rs Seed collection and filtering
hit.rs Hit filtering, MAPQ, parent/secondary
esterr.rs Divergence estimation
pe.rs Paired-end pairing
jump.rs Splice junction extension helpers
map.rs Core mapping pipeline
pipeline.rs Multi-threaded file mapping (SE + PE)
index/
mod.rs Index construction and queries
bucket.rs Hash bucket with hashbrown
io.rs Binary .mmi format I/O
chain/
mod.rs Scoring functions (comput_sc, mg_log2)
backtrack.rs Chain backtracking
dp.rs DP chaining algorithm
rmq.rs RMQ chaining with BTreeMap
align/
mod.rs Anchor-based alignment (align_skeleton)
ksw2.rs Scalar KSW2 (single + dual affine gap)
ksw2_simd.rs SIMD scaffold (runtime dispatch)
score.rs Scoring matrix generation
format/
mod.rs Output dispatch
paf.rs PAF formatting
sam.rs SAM formatting
cs.rs cs/MD tag generation
Testing
# Unit tests
cargo test
# Integration tests against C minimap2
cargo test --test integration
# Fixture parity matrix against C minimap2
scripts/parity_matrix.py
# Real-data conformance manifest
cp scripts/conformance_manifest.example.tsv scripts/conformance_manifest.local.tsv
$EDITOR scripts/conformance_manifest.local.tsv
scripts/conformance_matrix.py scripts/conformance_manifest.local.tsv
# Minimal public paired-end dataset setup
N_PAIRS=50000 scripts/prepare_minimal_conformance_data.sh
scripts/conformance_matrix.py data/conformance/ecoli_srr13321180/conformance_manifest.tsv
# Full local E. coli short-read and forced split-index validation, if raw FASTQs are present
scripts/conformance_matrix.py data/conformance/ecoli_srr13321180/conformance_full_manifest.tsv
# Small external HiFi, ONT, assembly, ALT, paired short-read, split-index, overlap, and RNA/splice data
scripts/prepare_external_small_conformance_data.sh
# Fast splice performance loop on the yeast RNA regression fixtures
scripts/benchmark_yeast_splice.py --reads 5000 --check-output
# Full raw yeast direct-RNA splice comparison (writes under /husky by default)
scripts/run_raw_rna_full_compare.sh
# Currently passing strict external categories
scripts/conformance_matrix.py data/conformance/external_small/conformance_manifest.tsv --category HiFi --category ONT --category Assembly --category ShortRead --category SplitIndex --category ALT --category Overlap --category RNA --diff-limit 40
# Heavier real-world external runs from the same downloaded inputs
scripts/conformance_matrix.py data/conformance/external_small/conformance_full_manifest.tsv
# All tests
cargo test --all
The conformance manifest runner is intended for datasets too large or site-specific to commit to this repository. Each row selects a comparison mode such as exact PAF, normalized PAF core fields, normalized SAM core fields, or SAM headers plus core fields.
Performance
2026-07-14 Public HG002 Matrix vs C minimap2
Original benchmark baseline: vendored C minimap2 v2.31 at commit
3c28777e7e2dcc90f825de1b9f17a89cca7d4452.
Data sources:
- hg38 FASTA from UCSC
https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.fa.gz. - HG002 benchmark inputs from Zenodo record 19703025, downloaded by
scripts/prepare_zenodo_19703025_hg38_data.sh. - Local
hg38.mmibuilt once with C minimap2. Index build time is reported separately and is not included in the mapping roll-up.
Commands used for the public-data rerun:
DATA_DIR=/data/henriksson/github/pres/pres_rustification/.tmp/minimap2_zenodo19703025 \
CASES=hifi,ont,wgs,hic RUN_COMPARE=0 \
scripts/prepare_zenodo_19703025_hg38_data.sh
minimap2/minimap2 \
-d /data/henriksson/github/pres/pres_rustification/.tmp/minimap2_zenodo19703025/hg38.mmi \
/data/henriksson/github/pres/pres_rustification/.tmp/minimap2_zenodo19703025/hg38.fa.gz
Mapping benchmarks were run serially with /usr/bin/time -v, -c, and
-t 30. Rust and C PAF outputs were byte-identical for every row.
| Case | Preset | Exact PAF parity | C wall | Rust wall | Original/Rust speedup | C peak RSS | Rust peak RSS | Rust/C RSS |
|---|---|---|---|---|---|---|---|---|
| HiFi 10k | map-hifi | yes | 55.63 s | 46.51 s | 1.196x | 17,430,108 KB | 15,787,840 KB | 0.906x |
| ONT 10k | lr:hq | yes | 58.67 s | 48.12 s | 1.219x | 17,480,416 KB | 16,573,672 KB | 0.948x |
| WGS 1M pairs | sr | yes | 58.70 s | 52.48 s | 1.119x | 8,662,260 KB | 8,784,792 KB | 1.014x |
| Hi-C 1M pairs | sr | yes | 65.99 s | 62.37 s | 1.058x | 8,716,532 KB | 8,732,012 KB | 1.002x |
Arithmetic mean mapping speedup is 1.15x original/Rust. Arithmetic mean Rust/C peak RSS ratio is 0.97x. The local hg38 index build took 85.75 s wall and 12,531,540 KB peak RSS with C minimap2.
License
MIT
Citing
This project is a translation of minimap2 by Heng Li. If you use it in published work, please cite the original minimap2 papers:
Li, H. (2018). Minimap2: pairwise alignment for nucleotide sequences. Bioinformatics, 34(18), 3094–3100. doi:10.1093/bioinformatics/bty191
Li, H. (2021). New strategies to improve minimap2 alignment accuracy. Bioinformatics, 37(23), 4572–4574. doi:10.1093/bioinformatics/btab705