# VCF INFO Field Annotations: How to Interpret It

The INFO field is the eighth column of a Variant Call Format (VCF) record, a single text field that holds key-value annotations about the variant described on that line. It carries the evidence the caller collected (depth, mapping quality, allele counts), the labels an annotation tool added (gene consequence, transcript, population frequency), and the assertions a clinical database supplied (pathogenicity, review status).

Interpretation succeeds or fails on this column. Two people can open the same VCF, read the same INFO string, and walk away with opposite conclusions if one of them assumes AF means the same thing everywhere or treats a dbSNP flag as a pathogenicity flag. This guide explains the grammar, the reserved vocabulary, the third-party namespaces, the checks that catch errors, and the specific misreadings that produce wrong answers in real analysis.

## What the INFO Field Actually Is

### The eight fixed columns

A VCF line has a fixed left-hand structure. CHROM names the reference sequence, POS gives the 1-based position, ID holds identifiers such as dbSNP rs numbers or a dot when there is none, REF gives the reference allele, ALT lists one or more alternate alleles separated by commas, QUAL is the phred-scaled quality that at least one alternate allele exists, FILTER names the filters the record failed (PASS when it failed none), and INFO carries the annotations. If the file contains genotypes, a FORMAT column and one column per sample follow.

The format was developed for the 1000 Genomes Project and published with the VCFtools description. The normative text is the VCF specification maintained in the hts-specs repository under the Global Alliance for Genomics and Health. Version 4.2 is the most widely implemented, and 4.3 adds features such as percent-encoding of special characters inside values. Files declare their version on the first line, for example `##fileformat=VCFv4.2`.

### The header is the contract

INFO keys are meaningless without their header. Every key must be declared on a `##INFO` line before the `#CHROM` line, using four attributes.

```
##INFO=<ID=AF,Number=A,Type=Float,Description="Allele frequency for each ALT allele, in the same order as listed">
```

ID is the key as it appears in the data. Number states how many values the key carries. Type states what kind of value each one is. Description is free text, and for third-party annotation tools the Description often embeds a machine-readable format string that tells you the field order. An INFO key that appears in the data but not in the header is a specification violation, and strict parsers will refuse the file.

The header can also carry Source and Version attributes, and VCF 4.3 introduced an IDX attribute that records display order. Treat IDX as cosmetic. The ID is what you match on.

### The five Type values

| Type | What it holds | Example value | Notes |
|--|--|--|--|
| Integer | A whole number | `DP=42` | Declared as a signed integer in the specification, so very large [structural variant](/blog/guides/structural-variant) spans can overflow strict parsers |
| Float | A decimal number | `AF=0.375` | Scientific notation and `NaN` appear in the wild, `NaN` usually marks an undefined value |
| Flag | A boolean with no value | `DB` | Number must be 0, presence means true and absence means false |
| Character | Exactly one character | `X` | Rare, Number must be 1 |
| String | Free text | `GENE1` | VCF 4.3 requires percent-encoding of reserved characters inside strings |

A Flag written with an explicit value is technically unusual. The specification defines presence as true. Some tools tolerate `DB=1`, some reject it, and a few writers emit explicit true or false strings. If a parser chokes on a Flag key, look for an explicit value before you look anywhere else.

## Decoding the Number Codes

Number is the part of the header that most often causes silent misinterpretation, because a mismatched count does not always throw an error. Some readers simply take the first value and discard the rest.

### Fixed integers

`Number=1` means one value. `Number=2` means exactly two. A fixed count above one is uncommon in INFO but legal.

### Number=A

One value per alternate allele, in the same order as ALT. This is the code behind almost every allele-specific annotation: AC, AF, and most VEP-derived frequency fields. If ALT is `G>A,T` then a conforming `AC` needs two values, `AC=3,1`, where 3 belongs to A and 1 belongs to T. Three values in a two-allele record is a malformed record.

### Number=R

One value per allele including the reference, so the count is the number of ALT alleles plus one. Read depth by allele is often stored this way, with the first value belonging to REF.

### Number=G

One value per genotype combination. For a biallelic site with diploid samples that means three values, corresponding to 0/0, 0/1 and 1/1. Number=G appears mainly in FORMAT fields such as genotype likelihoods rather than in INFO.

### Number=.

The dot means the number of values is unknown or variable, and values are comma-separated. Any consumer that iterates a Number=. field must read the whole list and not assume a length.

## A Worked Example, Key by Key

Consider a record at chromosome 1, position 12345, with REF `G` and ALT `A,T`, passing all filters, carrying this INFO content.

| Key | Value | Interpretation |
|--|--|--|
| AC | 3,1 | Three called alleles carry A, one called allele carries T |
| AN | 8 | Eight alleles were called across the samples in this file |
| AF | 0.375,0.125 | 3 divided by 8, and 1 divided by 8 |
| DP | 14 | Combined read depth across the samples at this site |
| MQ | 50.0 | Root mean square mapping quality of reads covering the site |
| DB | present | The record is a member of dbSNP, per the header description |
| SOMATIC | absent | Not flagged as a somatic observation |

The arithmetic is the part worth internalizing. AC divided by AN gives AF for each alternate allele. When those three do not agree, either the file was subset without recomputing the tags or an upstream tool rewrote one field and not the others. A four-sample VCF with `AN=8` and `AC=3,1` implies that among the eight called alleles, four are reference, three are A and one is T, so the genotypes are consistent with something like 0/1, 0/2, 0/0 and 1/1 across the four samples. If the sample columns in the same file show a different genotype configuration, the INFO allele counts were computed on a different sample set than the one you are looking at.

### Missing values versus absent keys

A dot is the missing value marker. `AF=.` means the key exists but the value could not be computed. The absence of the key means it was never written. Those are different statements and they should drive different downstream logic. Many pipelines treat absent and missing as interchangeable and then quietly drop candidate variants.

Sites-only VCFs are a common source of confusion here. Files distributed by population databases often have no FORMAT column and no sample columns. Their INFO AC, AN and AF describe the source cohort, not the samples you are holding. `AN=0` or `AF=NaN` in such a file usually means the field was undefined for that release, not that the variant is absent from all humans.

### Order and duplication

INFO key order carries no meaning. Do not write code that depends on AC appearing before AF, and do not assume a tool preserves order on rewrite. A key should not appear twice in one INFO field. When it does, most parsers keep the last occurrence silently, which is how contradictory annotations survive a round trip.

## Reserved Keys and Their Traps

The specification reserves a set of INFO keys. Reserved means "do not redefine this with a different meaning." It does not mean every tool obeys.

| Key | Type and Number | Meaning | Common misread |
|--|--|--|--|
| AC | Integer, A | Allele count in called genotypes | Treated as a population count when the file is a cohort subset |
| AN | Integer, 1 | Total called alleles | Compared across files with different sample sets |
| AF | Float, A | Allele frequency from AC and AN | Assumed to be a population frequency when it is a study frequency |
| DP | Integer, 1 | Combined depth across samples | Confused with the per-sample FORMAT DP |
| MQ | Float or Integer, 1 | Root mean square mapping quality | Read as an arithmetic mean |
| MQ0 | Integer, 1 | Count of reads with mapping quality zero | Ignored when judging multimapping |
| NS | Integer, 1 | Number of samples with data | Used as a proxy for cohort size |
| DB | Flag, 0 | Membership in dbSNP | Read as "known pathogenic variant" |
| VALIDATED | Flag, 0 | Validated by a follow-up experiment | Read as clinically classified |
| SOMATIC | Flag, 0 | Somatic observation | Read as confirmed tumor-only origin |
| END | Integer, 1 | End position of the described variant | Ignored for symbolic alleles, which truncates the event |
| AA | String, 1 | Ancestral allele | Assumed to be the reference allele |
| 1000G | Flag, 0 | Membership in 1000 Genomes | Read as frequency evidence |

The DB trap deserves its own sentence. dbSNP is a catalog of observed variation, and membership tells you only that someone has seen the allele before. A huge fraction of dbSNP entries have no frequency data and no clinical assertion. A pipeline that filters on DB to enrich for "real" variants is filtering on catalog history, not on biology.

MQ is the second most common trap. It is a root mean square, computed as the square root of the mean of squared mapping qualities. It behaves like a mean for most distributions but it is more sensitive to a small number of high-quality reads, so a site with many poorly mapped reads and three excellent ones can still show a respectable MQ. Pair MQ with MQ0 and with the per-sample depth before you decide the site is trustworthy.

END appears with symbolic alternate alleles such as `<DEL>` or `<DUP>`. In those records POS marks the start and END marks the last affected base, so the event length is END minus POS plus one. A structural variant read as a single base because END was ignored is a real and frequent error.

## Where the Annotation Keys Come From

Reserved keys cover calling evidence. Everything else is namespace territory, and namespace territory is where interpretation gets interesting.

### CSQ from Ensembl VEP

The Ensembl Variant Effect Predictor writes a single INFO key, CSQ, whose value is a comma-separated list of pipe-delimited consequence entries, one per transcript or per overlapping feature. The field order is not fixed across versions or command lines. It is declared in the header Description, which begins with a format string naming each position in order.

```
##INFO=<ID=CSQ,Number=.,Type=String,Description="Consequence annotations from Ensembl VEP. Format: Allele|Consequence|IMPACT|SYMBOL|Gene|...">
```

That Description is the only reliable guide to the payload. A truncated entry might look like `T|missense_variant|MODERATE|GENE1`, where the first field echoes the ALT allele the entry refers to. The full string in a real file typically continues with gene identifiers, transcript identifiers, biotype, exon and intron numbering, HGVS coding and protein names, existing variation identifiers, SIFT and PolyPhen predictions and more, in whatever order that particular run produced.

Three habits make CSQ usable. Split the field into one row per transcript before filtering, because a single variant can carry dozens of entries. Read the header before you index into positions. Filter on the Impact field rather than assuming the first entry is the most severe, since VEP's ordering follows transcript processing, not severity ranking.

### ANN from SnpEff

SnpEff writes ANN, a pipe-delimited entry with a standardized 16-field layout covering allele, annotation, impact, gene name, gene ID, feature type, feature ID, transcript biotype, rank, HGVS coding, HGVS protein, cDNA position, CDS position, protein position, distance, and an errors and warnings field. Because the layout is standardized, ANN is easier to parse positionally than CSQ, and the same caution applies: one variant produces many entries, and the first is not automatically the one that matters.

### BCSQ from bcftools csq

The bcftools consequence caller writes BCSQ with a shorter, different layout, also declared in the header. Its distinguishing feature is haplotype awareness: it considers the combination of nearby variants on the same read-backed haplotype rather than each allele in isolation. Two missense variants in cis can produce a different protein consequence than the same two variants in trans, and a per-allele annotator cannot see the difference. When a case looks like compound heterozygosity, a haplotype-aware annotation layer is worth adding.

### Population frequency keys

Large reference datasets distribute VCFs whose INFO fields carry AC, AN, AF and derived counts. The Genome Aggregation Database is the most widely used contemporary resource, with over 140,000 individuals in its flagship release, and the 1000 Genomes Project remains a foundational reference panel. Field names differ between database versions and between releases of the same database, so the header is again authoritative. Many releases add a maximum frequency across ancestry groups precisely because a single global AF hides structure. An allele that is rare overall can be common in one population, and that single fact changes a classification.

### Clinical assertion keys

ClinVar distributes VCFs whose INFO fields carry the assertion itself. CLNSIG holds the classification. CLNREVSTAT holds the review status, which encodes whether the assertion came from a single submitter, multiple submitters without conflicts, multiple submitters with conflicts, an expert panel, or a practice guideline. CLNDN names the condition. GENEINFO names the gene. The review status is not decoration. A one-star assertion and a three-star assertion are different grades of evidence, and a record with conflicting interpretations is explicitly telling you that the community has not converged.

### Custom keys

Labs add their own keys constantly. The safe convention is a stable prefix tied to the source, so that a future tool cannot collide with a reserved name. A key called `DP` that means something other than combined depth will corrupt every downstream consumer that trusts the specification. When you receive an unfamiliar VCF, list its INFO header lines before anything else.

## INFO Is Not the Only Annotation Layer

Three other layers get confused with INFO.

FILTER is a separate column. A PASS there means the record cleared whatever hard filters the pipeline applied. It says nothing about whether the annotations inside INFO are correct, current, or relevant.

FORMAT plus the sample columns hold per-sample values. The same key name can appear in both INFO and FORMAT with different meanings, and DP is the classic case. INFO DP is a site-level summary across samples. FORMAT DP is that one sample's depth. For a ten-sample VCF, the INFO DP is often not the sum of the ten FORMAT DP values, because the caller may have applied different read filters to the two computations. When you need per-sample depth, read FORMAT. When you need the site-level total the caller reported, read INFO.

External databases are a third layer. An INFO field that echoes a database value is a snapshot of that database at the time the annotation ran. Annotation files age. A frequency that was accurate at release can be stale two years later, and a classification can move from uncertain to pathogenic.

## Where VCF Sits Among Bioinformatics File Formats

VCF is one node in a chain. Understanding the neighbors clarifies what INFO can and cannot contain.

| Format | Content | Text or binary | Role in the pipeline |
|--|--|--|--|
| FASTQ | Reads plus per-base quality scores | Text | Raw sequencing output |
| FASTA | Sequences without quality scores | Text | Reference genomes and assembled contigs |
| SAM, BAM, CRAM | Read alignments to a reference | Text, then binary | Mapping output and the substrate for variant calling |
| BED | Genomic intervals | Text | Regions to call, capture targets, masks |
| GFF3 and GTF | Feature annotations on a reference | Text | Gene and transcript models |
| VCF and BCF | Variant records with INFO and genotypes | Text, then binary | Variant calling, annotation and delivery |

### FASTQ versus FASTA

FASTA stores a header line beginning with a greater-than sign followed by one or more lines of sequence. FASTQ stores four lines per record: a header beginning with an at sign, the sequence, a plus separator line, and a string of quality characters of exactly the same length as the sequence. That quality string is the whole difference, and it is a large one.

The quality characters encode a per-base error probability on a phred scale, usually offset by 33 in modern Illumina output. A base with a quality character corresponding to 30 has an estimated error probability of 1 in 1000. Those numbers drive adapter trimming, read filtering, overlap correction, and the base quality recalibration step that many variant callers expect. Nowhere in the resulting VCF will you find a per-base quality string. The quality information has been compressed into aggregate statistics such as BQ for root mean square base quality, MQ for mapping quality, and DP for depth. When you look at an INFO field saying `DP=14`, you are seeing the residue of millions of individual base quality estimates.

FASTA has no quality channel, so it cannot serve as raw read input. It is the format of reference assemblies and of consensus sequences. Confusing the two formats is a common first-week error: a FASTA passed to a read trimmer will produce nonsense because line two of every four is not a quality string.

### From FASTQ to VCF

The chain runs from FASTQ through alignment to BAM or CRAM, then through a variant caller to VCF or its binary equivalent BCF, then through annotation to a second VCF. Each hop loses information. The FASTQ quality strings become alignment scores become depth counts become INFO integers. Nothing downstream can recover detail that was dropped, which is why a suspicious INFO value is often best investigated by walking back up the chain rather than by staring harder at the VCF.

## How INFO Annotations Are Checked in Practice

### Structural validation

Start by confirming that the file parses and that the header declares every key used in the body. A validator such as vcf-validator from vcflib or the checks built into htslib will flag undeclared keys and Type violations.

### Header inspection

```
bcftools view -h cohort.vcf.gz | grep '^##INFO'
```

This lists every key with its Number, Type and Description. Read the Description of any third-party key. For CSQ and ANN, the format string inside the Description is the schema.

### Count consistency

For every Number=A field, the number of comma-separated values must equal the number of ALT alleles. Eyeballing a few records catches most problems.

```
bcftools query -f '%CHROM\t%POS\t%ALT\t%INFO/AC\t%INFO/AF\n' cohort.vcf.gz | head
```

A record with two ALT alleles and one AC value is malformed. A record with AC and AF values whose ratio does not match AN has a recomputation problem.

### Recomputation

Recompute the tags from the genotypes and compare.

```
bcftools +fill-tags cohort.vcf.gz -Ou -- -t AC,AN,AF | bcftools view -H | head
```

Disagreement between the stored AF and the recomputed AF localizes the fault to a subset step or an annotation step. Recomputation is also the correct repair when a cohort has been filtered down to a smaller sample set, because stored allele counts from the original cohort no longer describe the samples in the file.

### Normalization before joining

Databases match on representation. A variant written as a multi-allelic record will not match a database that stores each allele separately.

```
bcftools norm -m-any -f reference.fa cohort.vcf.gz -Oz -o cohort.split.vcf.gz
```

Splitting multi-allelic records, trimming shared bases and left-aligning indels before annotation removes an entire class of false negatives. Apply the same normalization on both sides of any join, and confirm that both files use the same genome build and the same contig naming.

### Parsing structured fields

```
bcftools +split-vep -f '%Allele\t%Consequence\t%IMPACT\t%SYMBOL' annotated.vcf.gz | head
```

This explodes CSQ into one row per transcript, which is the only workable shape for filtering. The same principle applies to ANN with the SnpEff or bcftools equivalents.

### Cross-source concordance

When a variant carries a frequency from one database and a classification from another, check that the coordinates and alleles agree. Discordance usually means a build mismatch or a normalization mismatch, not a biological surprise.

### When to distrust an annotation

Distrust an INFO value when its header is missing, when its Number does not match the allele count, when its value is the placeholder sentinel that the tool uses for undefined results, or when the record has been through an unknown number of reformatting steps without a version trail. These are all checkable conditions, and they are cheaper to check than to debug later.

## Clinical and Comparative Relevance

In clinical variant interpretation, population frequency and predicted consequence are inputs to a structured framework. The ACMG and AMP standards define evidence codes that include population data, computational predictions, functional data and segregation, with each code assigned a strength and the combination mapped to a classification. Nothing in that framework reads a VCF directly. The analyst reads the INFO fields, judges the quality of each source, and then assigns evidence codes.

This is why the review status field matters so much in practice. ClinVar exposes conflicting interpretations explicitly. A variant with three submitters and conflicting classifications is a variant where reasonable experts disagreed, and the presence of a single "Pathogenic" string in CLNSIG does not resolve that disagreement. Read CLNREVSTAT alongside CLNSIG every time.

The comparative picture is similar across species. Companion animal genomes have reference assemblies and variant databases hosted by the same major browsers that serve human data, and the same INFO vocabulary applies because the format is species-agnostic. The frequency databases differ, the sample sizes are usually far smaller, and a rare variant in a breed-restricted cohort can reach appreciable frequency through founder effects. Small AN values produce unstable AF estimates, so a frequency derived from a few dozen animals should carry much less weight than one derived from tens of thousands.

## Common Mistakes and Limitations

**Treating DB as a pathogenicity flag.** It means dbSNP membership. Filtering on it selects for catalog history.

**Confusing INFO DP with FORMAT DP.** They are computed differently and are not interchangeable. Use FORMAT when you need a sample-level number.

**Comparing AF across files with different sample sets.** AC divided by AN is a property of the cohort in the file. A cohort of 50 exomes and a population database of 140,000 people do not produce comparable numbers, and a variant absent from a small cohort is not absent from the population.

**Ignoring Number=A alignment.** When a multi-allelic record is split after annotation, the per-allele values must follow their alleles. Splitting with a tool that does not understand Number=A leaves the wrong value attached to the wrong allele.

**Reading CSQ or ANN as a single value.** Both are lists. The first entry is a transcript, not a verdict. Filter by impact and by canonical transcript status before drawing conclusions.

**Assuming Impact HIGH equals pathogenic.** Impact describes the predicted molecular consequence. A frameshift in a gene irrelevant to the phenotype is still HIGH impact and still not the answer.

**Skipping normalization before database joins.** Representation mismatches produce false negatives that look like absent annotations.

**Mismatching genome builds or contig names.** A file on GRCh38 joined to a database on GRCh37 will produce plausible-looking but wrong annotations at most positions. `chr1` and `1` are different strings and many tools treat them as different sequences.

**Ignoring FILTER because INFO looks good.** A record can carry a beautiful CSQ entry and still be a failed call. Read the FILTER column.

**Assuming a clinical classification is current.** Assertions change as evidence accumulates. Record the database version alongside the value.

**Overflowing Integer fields.** Structural variant spans and some counts can exceed the signed 32-bit range that strict parsers enforce for Integer. Large events may need to be handled as strings or split.

**Treating VCF as a report.** A VCF is an interchange format. It is not a validated clinical result, and the annotations inside it are only as good as the versions and parameters that produced them.

## Quick Review

- INFO is column eight, a set of key-value pairs separated by semicolons, with values inside a key separated by commas.
- Every key is defined by a `##INFO` header line giving ID, Number, Type and Description. The Description is the schema for third-party fields such as CSQ and ANN.
- Number=A means one value per ALT allele in ALT order. Number=R includes the reference. Number=G is per genotype. A dot means variable length.
- AC, AN and AF must be internally consistent, and all three describe the samples in the file, not the world.
- DB means dbSNP membership. It is not a pathogenicity flag.
- INFO DP is a site-level summary. FORMAT DP is per sample.
- Read the FILTER column and the database version before you trust any annotation.

## Frequently Asked Questions

### What does the INFO field in a VCF file mean?

It is the annotation column of a variant record, holding key-value pairs about that variant. The keys are declared in the file header with a defined Number and Type, and they carry calling evidence, functional consequence and database assertions.

### Why do some INFO keys have two comma-separated values?

Those keys use Number=A, which means one value per alternate allele. A record with two ALT alleles needs exactly two values, and the first belongs to the first ALT allele listed.

### Does the DB flag mean the variant is pathogenic?

No. DB records membership in dbSNP, which is a catalog of observed variation. Many dbSNP entries have no frequency data and no clinical interpretation.

### What is the difference between INFO DP and FORMAT DP?

INFO DP is a combined depth figure for the site across all samples as computed by the caller. FORMAT DP is that individual sample's depth. They can differ because the caller may apply different read filters to each calculation.

### Which entry in a CSQ field tells me the most severe consequence?

None by position. CSQ holds one entry per transcript, and the ordering is not a severity ranking. Read the header to learn the field layout, then filter on the IMPACT field and on canonical transcript status to find the entries that matter.

### Can I compare AF values from two different VCF files directly?

Only when the two files describe the same samples or the same population and were processed with the same pipeline. Otherwise each AF is a property of its own cohort, and a value from 50 samples is not comparable to one from a large reference database.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What does the INFO field in a VCF file mean?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "It is the annotation column of a variant record, holding key-value pairs about that variant. The keys are declared in the file header with a defined Number and Type, and they carry calling evidence, functional consequence and database assertions."
      }
    },
    {
      "@type": "Question",
      "name": "Why do some INFO keys have two comma-separated values?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Those keys use Number=A, which means one value per alternate allele. A record with two ALT alleles needs exactly two values, and the first belongs to the first ALT allele listed."
      }
    },
    {
      "@type": "Question",
      "name": "Does the DB flag mean the variant is pathogenic?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. DB records membership in dbSNP, which is a catalog of observed variation. Many dbSNP entries have no frequency data and no clinical interpretation."
      }
    },
    {
      "@type": "Question",
      "name": "What is the difference between INFO DP and FORMAT DP?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "INFO DP is a combined depth figure for the site across all samples as computed by the caller. FORMAT DP is that individual sample's depth. They can differ because the caller may apply different read filters to each calculation."
      }
    },
    {
      "@type": "Question",
      "name": "Which entry in a CSQ field tells me the most severe consequence?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "None by position. CSQ holds one entry per transcript, and the ordering is not a severity ranking. Read the header to learn the field layout, then filter on the IMPACT field and on canonical transcript status to find the entries that matter."
      }
    },
    {
      "@type": "Question",
      "name": "Can I compare AF values from two different VCF files directly?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Only when the two files describe the same samples or the same population and were processed with the same pipeline. Otherwise each AF is a property of its own cohort, and a value from 50 samples is not comparable to one from a large reference database."
      }
    }
  ]
}
</script>