Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CLI Reference

The vep binary accepts the Perl VEP command-line interface. Most flags have the same name and behavior; a flag marked “Accepted for VEP compatibility” below is parsed and has no effect on the annotation (the cache flags among them only name the cache path the output header prints), so an existing VEP command line is accepted. The annotation cache is always --json_cache.

# Show all flags
cargo run --release -- --help

# Short form
vep -i input.vcf -o output.txt --offline --json_cache /path/to/json_cache

Input

FlagTypeDefaultDescription
--input_file, -iStringSTDINInput file path (use STDIN for standard input)
--input_dataString–Accepted for VEP compatibility; not implemented (input is always read from --input_file)
--formatStringguessInput format: vcf, ensembl, hgvs, region. guess detects by file extension: .hgvs selects hgvs; anything else, including STDIN, is read as VCF

Output

FlagTypeDefaultDescription
--output_file, -oStringvariant_effect_output.txtOutput file path (use STDOUT for stdout)
--output_formatStringvepOutput format: vep, vcf, json, tab, parquet; any other value writes the default vep format. For parquet, the duckdb CLI must be on PATH (see Parquet section below).
--vcfboolfalseShorthand for --output_format vcf
--jsonboolfalseShorthand for --output_format json
--tabboolfalseShorthand for --output_format tab
--parquet_shapeStringnestedRow shape for --output_format=parquet. nested = one row per (record, allele): Uploaded_variation, Location, Allele and Existing_variation stay scalar and every other --tab column is a LIST (VARCHAR elements; DISTANCE INTEGER, STRAND TINYINT). flat = one row per (allele × transcript-consequence) tuple, every column scalar.
--compress_outputString–Accepted for VEP compatibility; not implemented (output is written uncompressed)
--force_overwrite, --forceboolfalseOverwrite output file if it exists
--no_headersboolfalseSuppress header lines in output (not for parquet, whose intermediate header is required)
--mask_header_cache_pathboolfalsePrint the cache directory as [PATH]/<leaf> in the ## Using cache in header line of the default and --tab formats, the cache= token of the VCF ##VEP line and the Parquet footer (VEP 116’s flag; vep-rs writes no statistics page)
--fieldsString–Accepted for VEP compatibility; not implemented (the columns follow the boolean field flags below)
--vcf_info_fieldStringCSQVCF INFO field name for annotations

Output parity

For the golden-corpus flag set (--offline --json_cache <dir> --species homo_sapiens --assembly <assembly> --buffer_size 5000 --no_stats --quiet plus one format flag), the default, --tab, --vcf and --json data rows match Ensembl VEP 116.2 apart from the consequence-term divergences the corpus manifests document; header lines that carry a time, a path, the command line or Perl API component versions match in shape. --vcf also switches on --symbol, --biotype and --numbers, as in VEP, and --json output is unescaped (VEP’s --no_escape behavior; vep-rs has no --no_escape flag). Under --everything, vep-rs also switches on --allele_number and --hgvsg, which VEP’s --everything does not, so the ALLELE_NUM and HGVSg header keys differ there. The formats, the header blocks and the golden-corpus tests are described in output-formats.md.

Parquet output

--output_format=parquet writes a TSV intermediate (one row per (allele × transcript-consequence) tuple) and post-processes it to a Hive-partitioned Parquet directory via a duckdb CLI subprocess. The intermediate is deleted on success unless the hidden --keep_intermediate is given. With -o STDOUT the TSV intermediate is streamed to stdout and no Parquet is written.

Requirements: the duckdb CLI, 1.2 or newer, must be on PATH. Install via brew install duckdb (macOS) or the CLI archive from https://duckdb.org/docs/installation/ (Linux: the duckdb_cli-linux-*.zip release asset). vep-rs checks for it after the FASTA, plugins and variation cache are loaded and before the first variant is read, and fails there if duckdb is missing or too old, so no annotation is spent on a run it cannot finalize.

Schema: five key columns (chrom, pos, end, ref, alt) then exactly the --tab columns in --tab order; pos/end are BIGINT, DISTANCE INTEGER, STRAND TINYINT, everything else VARCHAR with - stored as NULL, except the allele columns (ref, alt, Allele), where - is a real allele (a deletion’s ALT, an insertion’s REF) and is kept.

Writer options (all chosen for the reader): Parquet v2, ZSTD level 9, row groups of 122,880 rows sorted by (chrom, pos, ref, alt), a dictionary and a Bloom filter (0.1% false-positive rate) on every populated column of the flat shape (asserted by the parity tests; a column NULL throughout a row group has neither), the partition column stored inside the files, and the run’s identity (version, assembly, cache, command line, cache source versions) in the footer’s key-value metadata. The dictionary limit equals the row group size, which a flat column’s distinct values can never exceed; a LIST column of the nested shape keeps its dictionary and Bloom filter only while its distinct elements in a row group stay within that limit, so a column whose elements are mostly distinct, such as HGVSc, carries neither. The hidden --parquet_row_group_size N overrides the row group size (rounded up to a multiple of 2,048, DuckDB’s vector size, which the dictionary limit follows so that a row group with a distinct value per row keeps its Bloom filter); it exists so a small input can be written as several row groups under test.

Shape (--parquet_shape):

  • nested (default): one row per (record, allele); the per-consequence columns are LIST columns aligned index-wise. Query with UNNEST or list_contains:

    SELECT chrom, pos, ref, alt
    FROM read_parquet('out.parquet/**/*.parquet', hive_partitioning=false)
    WHERE list_contains(Feature, 'ENST00000366667')
      AND list_contains(IMPACT, 'HIGH');
    
  • flat: one row per (allele × transcript-consequence) tuple; every column scalar, so predicates push down directly:

    SELECT chrom, pos, ref, alt, Consequence, IMPACT
    FROM read_parquet('out.parquet/**/*.parquet', hive_partitioning=false)
    WHERE Feature = 'ENST00000366667' AND IMPACT = 'HIGH';
    

hive_partitioning=false keeps chrom as the stored VARCHAR; Hive type inference would otherwise read chrom=21 as a number.

Cache / Offline

FlagTypeDefaultDescription
--cacheboolfalseAccepted for VEP compatibility; no effect (the annotation cache is --json_cache)
--offlineboolfalseAccepted for VEP compatibility; sets --cache, which has no effect. vep-rs always runs offline
--dirString~/.vepAccepted for VEP compatibility; nothing is loaded from it. Heads the cache path printed in the output header when --dir_cache and --json_cache are absent
--dir_cacheString(same as --dir)Accepted for VEP compatibility; nothing is loaded from it. Only names the cache path printed in the output header when --json_cache is absent
--cache_versionu32116Accepted for VEP compatibility; selects no cache. Only the version in the header’s cache path when --json_cache is absent (defaults to the VEP release)
--json_cacheString–Path to the converted JSON cache directory: the only cache vep-rs reads. Without it no transcript is loaded and every variant is reported as intergenic_variant
--fasta, --faString–Indexed FASTA file (.fa + .fai) for reference sequences
--shift_3primeboolfalseEnable 3’ shifting of indels (requires --fasta)

The environment variable VEP_FASTA_STORAGE selects how the FASTA is held: mmap (default) maps the file, memory reads it into RAM; any other value is an error.

Species / Assembly

FlagTypeDefaultDescription
--species, -sStringhomo_sapiensAccepted for VEP compatibility; only names the species in the header’s cache path when --json_cache is absent. The data annotated is the --json_cache contents
--assembly, -aString–Genome assembly, GRCh37 or GRCh38 (hg19/hg38 are accepted; an unrecognized value warns and leaves the plugin guards inert). Names the assembly in the JSON output’s assembly_name and the Parquet footer metadata (without it the cache’s own assembly is used there), and is load-bearing for plugins: it picks the coordinate column a dual-coordinate database is indexed on and refuses a data file whose own assembly contradicts it. Pass it whenever --plugin is used. When --json_cache is absent the flag also supplies the _<assembly> suffix of the header’s cache path leaf, <version>_GRCh38; the leaf is the bare <version> when the flag is absent

Runtime

FlagTypeDefaultDescription
--buffer_sizeusize5000Number of variants per annotation batch
--max_sv_sizei6410000000A structural variant spanning more than this many bases is oversize; -1 lifts the limit, as in VEP 116. A <CNV:TR> record whose repeat sequence is longer than this stays symbolic rather than reading a direction of change (under -1 every one does), as in VEP 116. Ensembl VEP 116 drops an oversize record before annotation and writes nothing for it in any format; vep-rs annotates it: rows in the default, --tab and parquet outputs, its VCF line without consequences, no JSON object (output-formats.md, intended-divergences.md)
--fork, --threadsusize0Annotation worker threads. 0 = one per logical CPU, at most 32; pass 1 for single-threaded annotation, or any positive value to pin the count (not capped)
--decompression_threadsusize0BGZF decompression threads for .gz VCF input. 0 = one per logical CPU, capped at 10; a positive value is used as given
--distanceString5000Upstream/downstream distance in bp (or up,down)
--transcript_index_implStringbinHidden. Transcript overlap index implementation: bin, coitrees or sorted. All three produce the same overlap sets; the flag exists for benchmarking

Output Control

These flags control which annotation fields appear in the output (--coding_only and --no_intergenic are accepted and have no effect). --everything switches on VEP’s --everything set plus --allele_number and --hgvsg.

FlagTypeDefaultDescription
--everything, -eboolfalseSwitches on every flag in this table except --xref_refseq, --coding_only and --no_intergenic, every Allele Frequencies flag, --mirna, --allele_number, --sift b and --polyphen b. Implies --regulatory, so the not-implemented warning is logged on every --everything run
--symbolboolfalseGene symbol (e.g., BRCA1)
--biotypeboolfalseTranscript biotype
--canonicalboolfalseFlag canonical transcripts
--maneboolfalseMANE Select and MANE Plus Clinical flags
--mane_selectboolfalseMANE Select flag only
--tslboolfalseTranscript Support Level
--apprisboolfalseAPPRIS isoform annotation
--ccdsboolfalseCCDS transcript ID
--proteinboolfalseEnsembl protein ID
--protein_versionboolfalseAppend the translation version to the Ensembl protein ID (ENSP00000286808.3), unless it already carries one; prints nothing without --protein (VEP 116’s flag)
--uniprotboolfalseUniProt cross-references: SWISSPROT and TREMBL. The UNIPARC and UNIPROT_ISOFORM columns are added but never computed (always empty)
--xref_refseqboolfalseRefSeq transcript cross-references
--hgvsboolfalseHGVS coding and protein notations, and HGVS_OFFSET when an insertion or deletion was shifted 3’ along the transcript for them. As in Ensembl VEP 116, a deletion that runs over either end of the transcript is described over the bases inside it (ENST00000290239.6:c.-49_77+1248del), and a frameshift whose first changed residue is the stop codon reads as an extension, the count excluding the replaced stop (p.Ter124IleextTer14, not p.Ter124IlefsTer15)
--hgvsgboolfalseAccepted for VEP compatibility; HGVSg is not computed (the HGVSg column is added but always empty)
--siftString–SIFT predictions (p=prediction, s=score, b=both)
--polyphenString–PolyPhen predictions (p=prediction, s=score, b=both)
--numbersboolfalseExon/intron numbers
--domainsboolfalseAdds the DOMAINS column, which is never populated (see Compatibility with Perl VEP)
--regulatoryboolfalseAccepted for VEP compatibility; regulatory-feature annotation is not implemented and the flag warns
--regulatory_gffString–Refused with an error: it would annotate regulatory features and motifs from a GFF3 file in place of the cache, and regulatory annotation is not supported
--extended_promotersboolfalseRefused with an error: it would widen the promoters read with --regulatory_gff to their extended bounds, and regulatory annotation is not supported
--variant_classboolfalseVariant class (SO term)
--check_existingboolfalseCheck for co-located known variants
--coding_onlyboolfalseAccepted for VEP compatibility; not implemented
--no_intergenicboolfalseAccepted for VEP compatibility; not implemented

Allele Frequencies

FlagTypeDefaultDescription
--afboolfalseGlobal allele frequency (1000 Genomes Phase 3)
--af_1kgboolfalseContinental frequencies (AFR, AMR, EAS, EUR, SAS)
--af_gnomadeboolfalsegnomAD exome frequencies
--af_gnomadgboolfalsegnomAD genome frequencies
--max_afboolfalseHighest frequency across all populations
--pubmedboolfalsePubMed IDs for co-located variants
--gene_phenotypeboolfalseGene-phenotype associations

Filtering / Picking

FlagTypeDefaultDescription
--pickboolfalsePick one consequence per variant
--pick_alleleboolfalsePick one consequence per allele
--per_geneboolfalsePick one consequence per gene
--pick_allele_geneboolfalsePick one consequence per allele per gene
--most_severeboolfalseReport only the single most severe consequence
--summaryboolfalseReport a summary of all consequences
--flag_pickboolfalseFlag (but keep) non-picked consequences
--flag_pick_alleleboolfalseFlag non-picked per allele
--flag_pick_allele_geneboolfalseFlag non-picked per allele per gene
--pick_orderString–Accepted for VEP compatibility; not implemented. The pick order is fixed to VEP’s default (mane_select, mane_plus_clinical, canonical, appris, tsl, biotype, ccds, rank); the final length tie-break is not applied
--allele_numberboolfalseAdd allele number from input
--show_ref_alleleboolfalseShow reference allele in output
--minimalboolfalseAdds the MINIMISED column. Bi-allelic indels are always minimised, as VEP does regardless of the flag; per-allele minimisation of multi-allelic records is not implemented
--total_lengthboolfalseAccepted for VEP compatibility; not implemented

Plugins

FlagTypeDefaultDescription
--pluginString (repeatable)–Load a plugin: Name,param1,param2,.... Name is a built-in (the names in plugins.md, matched case-sensitively), the path of a C-ABI dylib, or a dylib name resolved as lib<Name>.so / lib<Name>.dylib under --dir_plugins. A name that is none of these is warned about and skipped (VEP’s own default); a dylib that exists but fails to open, reports another ABI version or fails init aborts the run
--customString (repeatable)–Accepted for VEP compatibility; not implemented (custom annotation sources are not loaded)
--custom_suppress_filterboolfalseRefused with an error: it would keep a --custom VCF source’s FILTER column out of the output unless the --custom source’s fields argument names it, and custom annotation is not supported
--dir_pluginsString–Directory searched for lib<Name>.so / lib<Name>.dylib when --plugin <Name> is neither a built-in nor a path

Dylib plugins implement ABI version 1 (vep_plugin_abi_version, vep_plugin_create, vep_plugin_init, vep_plugin_run, vep_plugin_free, vep_plugin_destroy, vep_plugin_name, vep_plugin_version). After the built-in plugins have run, each is called once per transcript consequence with the consequence and the variant as JSON and returns a JSON object whose entries become fields of the default format’s Extra column and of the --json output. The contract has no header symbol, so a dylib field carries no ## description line and no --tab or --vcf column. A run-time failure in a dylib plugin is logged as an error and the batch continues. crates/vep-plugin/examples/echo_plugin.rs is a working example (built as a cdylib) and crates/vep-cli/src/dylib_plugins.rs is the host side.

Transcript Sets

FlagTypeDefaultDescription
--refseqboolfalseAccepted for VEP compatibility; selects no transcript set (the transcript set is the --json_cache contents). Only suffixes the species directory of the header’s cache path, homo_sapiens_refseq, when --json_cache is absent
--mergedboolfalseAccepted for VEP compatibility; selects no transcript set (the transcript set is the --json_cache contents). Only suffixes the species directory of the header’s cache path, homo_sapiens_merged (homo_sapiens_refseq_merged with --refseq), when --json_cache is absent
--gencode_basicboolfalseAccepted for VEP compatibility; not implemented (the transcript set is the --json_cache contents)

Statistics

FlagTypeDefaultDescription
--no_statsboolfalseAccepted for VEP compatibility; not implemented (no statistics file is written, with or without it)
--stats_fileString–Accepted for VEP compatibility; not implemented (no statistics file is written)
--stats_textboolfalseAccepted for VEP compatibility; not implemented (no statistics file is written)

Verbosity

FlagTypeDefaultDescription
--verbose, -vboolfalseDebug-level logging (to stderr)
--quiet, -qboolfalseSuppress status/progress messages and warnings; only errors are logged

Miscellaneous

FlagTypeDefaultDescription
--dont_skipboolfalseAbort the run on a variant that fails parsing instead of skipping it (VEP keeps the variant); adds the CHECK_REF column, which is never computed (always empty)
--allow_non_variantboolfalseWith --vcf output, write non-variant VCF records (ALT=.) through unchanged; ignored for the other output formats
--mirnaboolfalseAccepted for VEP compatibility; miRNA secondary structure is not computed (the miRNA column is added but always empty)

Compatibility with Perl VEP

What the flag tables above mark “Accepted for VEP compatibility” is the whole list of Perl VEP behaviour vep-rs does not implement; this section gathers it.

Consequence terms never assigned. Six regulatory-feature terms (TFBS_ablation, TFBS_amplification, TF_binding_site_variant, regulatory_region_ablation, regulatory_region_amplification, regulatory_region_variant) need a regulatory-feature cache that is not loaded: --regulatory, alone or through --everything, is accepted and warns that regulatory-feature annotation is not implemented. The root term sequence_variant has no predicate, and Perl VEP’s consequence engine never assigns it either. The other 34 of Perl VEP’s 41 Sequence Ontology terms are assigned.

Input formats. --format takes vcf, ensembl (the tab-delimited default format), hgvs and region (chr:start-end/allele and chr:start-end:strand/allele), or guess. HGVS input is genomic (:g.) only; :c., :n., :p. and :r. notation is rejected as not implemented. The id, spdi and caid formats are not read: Perl VEP resolves all three through its variation database and refuses them in --offline mode.

Refused flags. Three Ensembl VEP 116 flags are declared so that the command line names them, and refused with an error that says what each would do: --regulatory_gff and --extended_promoters belong to regulatory annotation, --custom_suppress_filter to custom annotation; neither is supported.

No database mode. vep-rs is offline-first and never contacts a database; --database, --host, --port, --user and --password do not exist and are rejected as unknown flags. The transcript set is the --json_cache contents (cache-setup.md), so --refseq, --merged and --gencode_basic select nothing.

Accepted without effect. --custom (custom annotation files are not processed); --regulatory; the statistics flags --stats_file, --stats_text and --no_stats (no statistics file is written with or without them); --mirna (the miRNA column is added and always empty); --cache, --offline, --dir, --dir_cache and --cache_version (they locate no cache; see the Cache table); --coding_only and --pick_order. Protein domains are never mapped: the DOMAINS field exists and protein features are read from the cache, but --domains leaves the column empty, and the native cache builder writes no domain features (the Ensembl GFF3 it reads carries none).

Examples

Basic offline annotation

vep -i input.vcf -o output.txt \
    --offline --cache \
    --json_cache /path/to/json_cache \
    --species homo_sapiens --assembly GRCh37

VCF output with common fields

vep -i input.vcf -o annotated.vcf \
    --vcf --offline --cache \
    --json_cache /path/to/json_cache \
    --everything

JSON output

vep -i input.vcf -o output.json \
    --json --offline --cache \
    --json_cache /path/to/json_cache \
    --everything

Clinical plugins

vep -i input.vcf -o output.txt \
    --offline --cache --json_cache /path/to/json_cache \
    --assembly GRCh38 \
    --plugin CADD,snv=/path/to/cadd/whole_genome_SNVs.tsv.gz,indels=/path/to/cadd/gnomad.genomes.r4.0.indel.tsv.gz \
    --plugin REVEL,file=/path/to/revel/revel_scores.tsv.gz \
    --plugin SpliceAI,snv=/path/to/spliceai/spliceai_scores.raw.snv.vcf.gz \
    --everything --force

--assembly is not optional here. CADD and dbscSNV use it to reject a data file built from the other genome; REVEL uses it to select which of its two coordinate columns to read and rejects a copy whose tabix index was built on the other column. Without it those guards are inert and REVEL falls back to the GRCh37 column with a warning, so a GRCh38-indexed file annotates nothing. SpliceAI also accepts indel= and cutoff=; only the openly published GRCh38 SNV file is validated, and the indel files, distributed through Illumina BaseSpace, are unsupported data rather than a rejected parameter (see plugins.md).

Parallel annotation

vep -i large_input.vcf -o output.txt \
    --offline --cache --json_cache /path/to/json_cache \
    --fork 8 --buffer_size 10000

Filtered output (one consequence per allele per gene)

vep -i input.vcf -o output.txt \
    --offline --cache --json_cache /path/to/json_cache \
    --pick_allele_gene --canonical \
    --everything