Skip to content

ANNOVAR: how to annotate your own genome variants and read the output

Oak
A long pale strand strung between forest trunks, tagged with colored glowing markers by hovering moth-like creatures in misty blue darkness.

ANNOVAR is a Perl program that takes a list of genetic variants and attaches meaning to each one. It reports which gene and transcript the variant falls in and what it does to the protein. It also reports how common it is in population databases, and what external databases such as ClinVar say about it 1. You run it locally on a VCF (Variant Call Format) file from your own sequencing, it writes a tab-delimited table with one row per variant, and you filter that table. It assembles the evidence you would need to decide. ANNOVAR is not a classifier and it does not tell you whether a variant matters. The decisions themselves belong to you and, for anything clinical, to a clinician.

Below is how we would run it on a personal whole genome, the input preparation that determines whether the output is correct, and the specific places where ANNOVAR’s answer differs from other tools.

The three annotation types

ANNOVAR organizes everything into three operations, and understanding the split makes the command line readable. Gene-based annotation (“g”) takes a gene model such as RefSeq and reports the consequence of each variant on transcripts, plus an amino acid change for coding variants. The consequence may be exonic, intronic, or splicing. It may also be UTR5, upstream, or intergenic. Region-based annotation (“r”) asks whether a variant overlaps an interval, such as a conserved element or a cytoband. Filter-based annotation (“f”) looks up the exact variant in a database and returns stored values. The lookup key is chromosome, position, reference allele and alternate allele. This is how allele frequencies, ClinVar records, and precomputed deleteriousness scores are attached 2.

Two programs matter in practice. annotate_variation.pl runs one annotation at a time and downloads databases. table_annovar.pl runs many annotations in one pass and merges them into a single wide table, which is what you want for a personal genome.

Downloading databases

ANNOVAR ships with almost no data. You download each database into a humandb/ directory, and the total for a useful whole-genome set runs to tens of gigabytes, so put it on a disk you do not mind filling.

cd annovar
for db in refGene ensGene knownGene avsnp150 clinvar_20240917 \
          gnomad41_genome dbnsfp47a dbscsnv11 ; do
  perl annotate_variation.pl -buildver hg38 -downdb -webfrom annovar $db humandb/
done
# cytoBand comes from UCSC, not the ANNOVAR mirror:
perl annotate_variation.pl -buildver hg38 -downdb cytoBand humandb/

Two notes on this step. The -webfrom annovar flag is required for the curated databases. Without it ANNOVAR looks at UCSC and fails for most names. And the gene-based databases need their transcript FASTA (hg38_refGeneMrna.fa) for protein-level annotation, which the download provides. If you build a custom gene definition you must also build the FASTA with retrieve_seq_from_fasta.pl, or every coding variant comes back as UNKNOWN.

Check the build. Mixing an hg19 VCF with hg38 databases produces a complete, plausible, entirely wrong table. ANNOVAR will not warn you.

Preparing the VCF

Most bad ANNOVAR output traces back to the input file rather than to ANNOVAR. Three problems dominate, and all three are fixable before annotation.

First, multi-allelic sites. A record with ALT=A,AT is one line with two variants. ANNOVAR’s VCF reader handles these, but downstream joins and per-variant filtering get much simpler if you split them first. Second, indel representation. Filter-based lookups are exact string matches on position and alleles, so an indel that is not left-aligned and parsimonious will silently miss its gnomAD or ClinVar record. Third, contig naming, since chr1 and 1 are different keys.

bcftools norm -m-both -f GRCh38.fa -c s sample.vcf.gz \
  | bcftools annotate --rename-chrs chr_map.txt -Oz -o sample.norm.vcf.gz
bcftools index sample.norm.vcf.gz

Then run the annotation. We prefer -vcfinput so that genotype, depth, and quality fields survive into the output. We also use -polish so that indel-affected protein changes are reported correctly rather than as a bare frameshift call.

perl table_annovar.pl sample.norm.vcf.gz humandb/ \
  -buildver hg38 \
  -out sample.annot \
  -remove \
  -protocol refGene,ensGene,cytoBand,avsnp150,gnomad41_genome,clinvar_20240917,dbnsfp47a,dbscsnv11 \
  -operation g,g,r,f,f,f,f,f \
  -argument '-hgvs -splicing_threshold 10',,,,,,, \
  -nastring . \
  -polish \
  -vcfinput \
  -thread 8

The -argument string is positional and must have one comma-separated slot per protocol entry, including empty ones. -hgvs asks for HGVS-style coding notation instead of ANNOVAR’s default. -splicing_threshold 10 widens the window around exon boundaries that counts as splicing. The default is 2 bases, which misses variants that splice-scoring tools such as dbscSNV flag. Output is sample.annot.hg38_multianno.txt plus a VCF carrying the same fields in INFO.

Expect roughly half an hour to a few hours for a whole genome with these databases on a workstation, dominated by the dbNSFP and gnomAD filter steps and by disk read speed. The original paper reported annotation of a human exome in a few minutes, which is accurate for a small gene-based run and not for this protocol 1.

Reading the output

The columns you will use most are these.

  • Func.refGene (exonic, splicing, intronic, and so on)
  • Gene.refGene
  • ExonicFunc.refGene (nonsynonymous, stopgain, frameshift deletion)
  • AAChange.refGene, which lists one entry per transcript

A single missense variant in a gene with eight RefSeq transcripts produces eight comma-separated entries with different codon numbers. That is correct behavior and it is why you cannot treat AAChange as a single value.

For a personal genome, the filter that cuts the table down fastest is population frequency. Restricting to AF < 0.001 in gnomAD and to ExonicFunc in the loss-of-function categories takes a whole genome from roughly four to five million variants to a few hundred rows. Add CLNSIG from ClinVar as a separate axis, since a variant can be well known and common. Pipe through awk or load the table into a dataframe. It is a plain TSV.

Be careful with the score columns from dbNSFP. They are precomputed predictions, they disagree with each other often, and none of them establishes that a variant affects your health.

Transcript choice changes the answer

The most important limitation is not a bug. Annotation output depends on which gene model you use and which tool computes the consequence. Comparing RefSeq to Ensembl transcripts, or ANNOVAR to VEP, changes the reported consequence for a substantial fraction of variants. That includes a meaningful share of loss-of-function calls 3. This is why the command above runs both refGene and ensGene in the same pass: disagreement between the two columns is a signal that a variant needs manual review in a genome browser.

The same caution applies to nomenclature. Annotation tools disagree on HGVS syntax for variants that are cataloged in ClinVar, which breaks naive string matching between your table and an external record 4. Match on genomic coordinates and alleles where you can, and treat the HGVS string as a label for humans. Independent evaluations of clinical annotation pipelines have found comparable discordance across tools and emphasize validating whatever pipeline you settle on against a known truth set 5.

If you would rather not manage the databases, wANNOVAR runs the same engine as a web service and accepts a VCF or a variant list, at the cost of uploading your genome to someone else’s server 6. Larger aggregation pipelines such as WGSA precompute far more annotation fields per variant and are designed for whole-genome study scale rather than one person 7. VarAFT wraps ANNOVAR annotations in a filtering interface if you prefer a GUI 8, and variant tools offers an alternative annotation and analysis framework built around its own database of variants 9.

One practical note: ANNOVAR is free for personal and academic use and requires a license for commercial use. Registration is needed to get the download link.

Questions people also ask

What is the difference between ANNOVAR and VEP? Both map variants onto transcripts and report consequences. ANNOVAR is a lightweight Perl program with local flat-file databases and a wide-table output, while VEP is maintained by Ensembl and defaults to Ensembl transcripts. Their consequence calls differ on a nontrivial fraction of variants, largely because of gene model and rule differences 3.

Does ANNOVAR work on hg38? Yes. Pass -buildver hg38 and download the hg38 versions of every database. There is no automatic liftover, and mixing builds fails silently.

Can ANNOVAR tell me if a variant is pathogenic? No. It reports what other databases say, including ClinVar’s clinical significance field and predicted deleteriousness scores. Classification is a separate process with defined evidence criteria, and any result you intend to act on should go to a clinical genetics professional for confirmation by an accredited laboratory.

What input formats does it accept? Its native format is avinput, a five-column file. The columns are chromosome, start, end, reference allele, and alternate allele, with - marking absent bases in indels. The script convert2annovar.pl converts VCF, and table_annovar.pl -vcfinput handles VCF directly while preserving genotype fields 2.

Why are some of my variants annotated as UNKNOWN? Usually the transcript FASTA for your gene definition is missing or out of sync with the annotation table, so ANNOVAR cannot translate the codon. Re-download the gene database, or rebuild the FASTA with retrieve_seq_from_fasta.pl.

Footnotes

  1. K. Wang, M. Li, H. Hakonarson. ANNOVAR: functional annotation of genetic variants from high-throughput sequencing data. Nucleic Acids Research, 2010. https://doi.org/10.1093/nar/gkq603 ↩ ↩2

  2. Hui Yang, Kai Wang. Genomic variant annotation and prioritization with ANNOVAR and wANNOVAR. Nature Protocols, 2015. https://doi.org/10.1038/nprot.2015.105 ↩ ↩2

  3. Davis J McCarthy, Peter Humburg, Alexander Kanapin, et al. Choice of transcripts and software has a large effect on variant annotation. Genome Medicine, 2014. https://doi.org/10.1186/gm543 ↩ ↩2

  4. Yu-An Chen, Tzu-Hang Yuan, Jia-Hsin Huang, et al. Toward streamline variant classification: discrepancies in variant nomenclature and syntax for ClinVar pathogenic variants across annotation tools. Human Genomics, 2025. https://doi.org/10.1186/s40246-025-00778-x ↩

  5. Sachleen Tuteja, Sabah Kadri, Kai Lee Yap. A performance evaluation study: Variant annotation tools - the enigma of clinical next generation sequencing (NGS) based genetic testing. Journal of Pathology Informatics, 2022. https://doi.org/10.1016/j.jpi.2022.100130 ↩

  6. Xiao Chang, Kai Wang. wANNOVAR: annotating genetic variants for personal genomes via the web. Journal of Medical Genetics, 2012. https://doi.org/10.1136/jmedgenet-2012-100918 ↩

  7. Xiaoming Liu, Simon White, Bo Peng, et al. WGSA: an annotation pipeline for human genome sequencing studies. Journal of Medical Genetics, 2015. https://doi.org/10.1136/jmedgenet-2015-103423 ↩

  8. Jean-Pierre Desvignes, Marc Bartoli, Valérie Delague, et al. VarAFT: a variant annotation and filtration system for human next generation sequencing data. Nucleic Acids Research, 2018. https://doi.org/10.1093/nar/gky471 ↩

  9. F. Anthony San Lucas, Gao Wang, Paul Scheet, et al. Integrated annotation and analysis of genetic variants from next-generation sequencing studies with variant tools. Bioinformatics, 2011. https://doi.org/10.1093/bioinformatics/btr667 ↩

Pothos builds longitudinal molecular profiles of individuals: whole-genome sequencing, single-cell RNA sequencing, and plasma proteomics, delivered as a detailed report, every data file, and stored cells. Build your profile.