DePPA.jl is a high-performance, pure Julia package for multiple sequence alignment (MSA) analysis and degenerate PCR primer design. It natively handles IUPAC degenerate sequences and provides rigorous statistical calculations for the thermodynamic properties of complex primer pools.
Most standard bioinformatics tools (like Primer3) are designed exclusively for single, pure sequences and cannot natively process MSAs. Commercial suites (Geneious, CLC) offer basic IUPAC support but often rely on simplistic consensus algorithms that ignore the thermodynamic reality of mixed primer pools.
DePPA.jl takes an MSA as its primary input, identifies conserved regions, and constructs degenerate primers capable of amplifying entire gene families simultaneously.
To ensure successful PCR amplification across all target variants, DePPA.jl evaluates the statistical distribution of thermodynamic parameters for the entire primer pool, rather than a single "average" sequence:
-
$T_m$ (Melting Temperature): Calculates the distribution of melting temperatures across all variants to prevent amplification bias. -
$\Delta G$ (Gibbs Free Energy): Evaluates the stability of the primer-template duplex for all variants, ensuring no sequence forms excessively stable secondary structures or binds too weakly.
The computational engine for nearest-neighbor (NN) thermodynamics is powered by extending the functionality of SeqFold.jl. While SeqFold natively calculates properties for non-degenerate sequences, DePPA.jl expands degenerate oligos into their non-degenerate variants, computes the thermodynamics for each independently, and aggregates the results into a statistical distribution. The underlying NN parameters and complex salt corrections are based on the foundational biophysical models of SantaLucia & Hicks (2004) and Owczarzy et al. (2008).
While several tools exist for PCR primer design, they fundamentally differ in their handling of alignments and degenerate sequences.
DePPA.jl is designed to be highly interactive directly from the Julia REPL. It features rich, color-coded terminal output for alignments and primers.
MAFFT_jllis used for automatic alignment, andSeqFoldserves as the backend for nearest-neighbor thermodynamic calculations.
julia> using Pkg
julia> Pkg.add("DePPA.jl")
julia> using DePPA.Alignments, DePPA.Primers, DePPA.Oligos
julia> using SeqFold, MAFFT_jll
# Optional: set the REPL visualization style (:bw, :polymorf, or :allcolors)
julia> setMSAShowStyle!(:bw);
# Optional: set the consensus type shown above the MSA (:major, :degen)
julia> setMSAconsensusShowType!(:major);julia> data = """>1
GATCTGTAATGAGCGGCAGACCGACCGCGAATTAGACCTCGC
CGAAGCCCTGGCCGCCAAGCTCAATTCGAAGCTCATTCAC
>2
CATTTGCAACGAGCGTCAGACCGACCGCGAACTCGACCTGGC
CGAAGCGCTGGCTGCCAAACTCAATTCTAAGCTCATC
>3
CATTTGTAACGAGCGTCAGACCGACCGTGAACTCGACCTCGC
CGAGCTGCCAAACTCAATTCCAAGCTCATCCACTT
>4
CTGTAACGAGCGGCAGACTGACCGAGAATTAGACCTCGCTGA
AGCGCTGGCCGCCAAGCTCAATTCGAAGCTCATTCACTTTG
>5
TGTAACGAGCGGCAGACTGACCGAGAATTAGACCTCGCTGAA
GCGCTGGCCGCCAAGCTCAATTCGAAGCTCATTCACTTAG""";
julia> temp_fasta = tempname(); open(temp_fasta, "w") do f write(f, data) end;
julia> alignment = MSA(temp_fasta; mafft=true)
MSA with 5 sequences of length 86:
CATCTGTAACGAGCGGCAGACCGACCGAGAATTAGACCTCGCCGAAGCGCTGGCCGCCAAGCTCAATTCGAAGCTCATTCACTT--
1 >G..C.....T.................C....................C.................................----
2 >C.....C........T...........C...C.C.....G..............T.....A........T........C-------
3 >C..............T...........T...C.C...........-------..T.....A........C........C.....--
4 >---C.................T....................T.........................................TG
5 >----.................T....................T.........................................AG
1 · · · · ⌢ · · · 86The engine scans the alignment, filtering candidates based on reasonable default parameters, but you always can adjust them. Reach to the documentation for further details.
Custom Base.show method for Vector with primers facilitates the crude preview of forward and reverse primer distribution for the alignment.
julia> primers = construct_primers(alignment)
Constructing primers… 100%|██████████| Time: 0:00:00
Primer distribution for 5 seq MSA (L=86): 94 primers
32 ┤ ▃▅▅▅▆██████▆▃
│ ▁▆█████████████▇▂▂▂
│ ▂▂▂▂▂▄▅ ▁▁▁▁▁▁▁ ▅███████████████████▆▁
│ ▂▄▇████████▇█████████▇▃ ▂▇██████████████████████▄
│ ▁▃▅▇██████████████████████████████▇▇▇▇▇▇▇▅▃▅██████████████████████████▅▂▂▂▂
0 ┼ ╞════════════════════════════════════════════════════════════════════════════════
│ ▔▔▔▔▔▔█████████████████████▀▀▀▀▀▀▔▔▔████████████████████████▀▀▔▔
│ ▔▔▔▔▔▀▀▀▀▀█████████▀▔ ▔████████████████████▀▔▔
│ ▔▔▔▔▔▔▔▔▔ ▔█████████████████▀▔
│ ▔▔▔▀███████████▀▔
32 ┤ ▔▔▔▔▔▔▔▔▔▔▔
1 86best_pairs matches primers based on chosen amplicon length and :tm, :tm_diff, :startpos, :length).
julia> primer_pairs = best_pairs(primers; amplicon_len=40:50, sortby=:startpos)
97 PCR primer pairs for 5 seq. MSA:
|==============================================================86| Tm °C
[ 1] >-------------46bp--------------< 56.2±1.9
[ 2] >--------------48bp---------------< 57.4±0.7
[ 3] >-------------45bp-------------< 55.8±1.4
[ 4] >--------------47bp--------------< 57.0±0.3
[ 5] >--------------47bp--------------< 58.6±1.8
[ 6] >------------44bp-------------< 55.2±0.9
... 85 more ... ...
[92] >--------------47bp--------------< 56.4±0.6
[93] >--------------48bp---------------< 55.6±1.4
[94] >--------------48bp---------------< 57.4±0.4
[95] >--------------49bp---------------< 55.9±1.1
[96] >--------------49bp---------------< 57.6±0.6
[97] >---------------50bp---------------< 56.3±0.7Before exporting you'd better name the primer pairs, you've just constructed:
julia> a1 = reannotated(primer_pairs[6], "AMPL_1")
PCR primer pair for 5 seq. MSA, amplicon: 6:49 (44bp)
>________________44bp_________________<
|==============================================================================86|
Forward: GYAAYGAGCGKCAGACYGAC at 6:25 (AMPL_1)
Reverse: SGCTTCRGCSAGGTCKARTTC at 29:49 (AMPL_1)
Tm: 55.2±0.9 °C
julia> a2 = reannotated(primer_pairs[92], "AMPL_2")
PCR primer pair for 5 seq. MSA, amplicon: 30:76 (47bp)
>__________________47bp___________________<
|==============================================================================86|
Forward: AAYTMGACCTSGCYGAAGCSCTG at 30:52 (AMPL_2)
Reverse: GAGCTTVGAATTGAGYTTGGC at 56:76 (AMPL_2)
Tm: 56.4±0.6 °CNow you are free to export your sequences!
julia> export_evrogen(stdout, [a1, a2], scale=0.02)
AMPL_1_F_6; GYAAYGAGCGKCAGACYGAC; 0.02
AMPL_1_R_49; SGCTTCRGCSAGGTCKARTTC; 0.02
AMPL_2_F_30; AAYTMGACCTSGCYGAAGCSCTG; 0.02
AMPL_2_R_76; GAGCTTVGAATTGAGYTTGGC; 0.02
julia> export_evrogen("primers.txt", [a1, a2], scale=0.02)
"primers.txt"DePPA.jl can be seamlessly integrated into Python bioinformatics pipelines using juliacall.
$ uv add juliacall
$ uv run pythonIn Python REPL:
>>> from juliacall import Main as jl
>>> jl.seval("""using Pkg; Pkg.add("DePPA"); Pkg.add("SeqFold")""")
>>> jl.seval("using DePPA.Oligos, SeqFold")
# Define convenient wrapper
>>> jl.seval('calc_tm(seq::String) = tm(DegenOligo(seq))')
>>> result = jl.calc_tm("AGACYGACCGHGAAYTMGACCT")
>>> print(f"Mean Tm: {result.mean}, Confidence: {result.conf}")
Mean Tm: 55.7, Confidence: (44.2, 65.6)- SantaLucia, J., & Hicks, D. (2004). Thermodynamics of DNA-RNA interactions and DNA-DNA interactions. Annual Review of Biophysics and Biomolecular Structure, 33, 415-440.
- Owczarzy, R., Moreira, B. G., You, Y., Behlke, M. A., Walder, J. A., & Walder, J. (2008). Effects of sodium, magnesium, and spermidine on the stability of DNA duplexes. Biochemistry, 47(20), 5336-5353.
- SeqFold.jl — The underlying nearest-neighbor thermodynamic engine.
If you use DePPA.jl in your research, please cite:
@misc{DePPA.jl,
author = {A.D. Bezlepsky},
title = {{DePPA.jl: Degenerate Primer Pair Assembler}},
year = {2026},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/phlaster/DePPA.jl}},
}