Primer & probe design for any organism: from a gene name to checked oligos in minutes.
Features · Quick start · How it works · Architecture · Development
Primerool fetches genes live from Ensembl or NCBI, lays them out as an interactive sequence map, and lets you place primers and probes by hand or have them designed for you. Every oligo is checked right away for Tm, GC content, hairpins and dimers by its own native thermodynamics engine, Strider. You don't need genome files, a database or an install: open it in a browser.
| 51 preset species across animals, plants, bacteria, fungi, protists and viruses, plus any Ensembl species name. You can also paste an accession or a raw sequence. | Select bases, right-click and choose what to make. Drag a primer to move it, or drag its end to resize it. Everything is recomputed as you go. | Strider (native Rust nearest-neighbour + Mathews 2004 folding) picks and checks every oligo, with an IDT OligoAnalyzer Tm next to Strider's when you want a second opinion. |
| General PCR, whole-gene (WGA), exon–exon junction (qRT-PCR), ARMS allele-specific, TaqMan and allele-detection probes. | MAFFT multiple alignment shown the classic way (numbered rows and a match line), plus primers designed in conserved regions. | Primer sets remembered per sequence, sessions saved to a file or autosaved, and light/dark themes with your own accent colour. |
- Search by gene name (e.g. BRCA1, CSN2) or accession (e.g.
NM_001443849.1). An accession is identified through NCBI BLAST and resolved to its gene. - Ensembl REST or NCBI E-utilities: switch sources whenever one of them is slow.
- Every annotated transcript is listed, with the canonical one pre-selected. You choose genomic DNA (with introns) or spliced mRNA, with or without UTRs, and with upstream/downstream flanks of any length.
- Custom sequences: paste any sequence and design on it directly.
- SNP batch import: upload a per-variant flanking-sequence report (
.docx,[REF/ALT]-marked) and design flanking primers for every SNP in one go.
- Sequence map:
- CDS, UTRs, flanks and introns in their own colours; introns can be collapsed to their length.
- Hover any base for its position in the gene and its genomic coordinate.
- Find in sequence: a literal search (optionally the reverse complement too) or an rsID lookup that pins the SNP on the map.
- Align in sequence: Smith–Waterman finds where a pasted primer or amplicon binds best, mismatches included.
- Feature map: a zoomable overview of exons, introns, CDS and UTRs, with your primers overlaid.
- Exon map: the spliced transcript exon by exon, for placing junction primers where they cross the splice site.
By hand. Select bases on any map and right-click:
| Pick | What it makes |
|---|---|
| General | A forward or reverse primer anywhere in the gene |
| WGA (flank) | Primers in the flanks, to amplify the whole locus |
| Junction | A primer spanning an exon–exon junction; its partner may sit anywhere in the gene |
| ARMS twins / common | Allele-specific wild-type/mutant twins with their 3′ end on the SNP, plus the common primer |
| Probe: general | A TaqMan hydrolysis probe |
| Probe: allele detection | A wild-type/mutant probe pair differing only at the SNP |
| BLAST · Secondary structures | For any selection, or any placed primer |
Placed primers and probes can be dragged to move or resized by their ends on both the sequence map and the exon map. ARMS twins keep their 3′ end locked on the SNP, allele probes can't lose their SNP, and each mutant partner follows its wild-type twin.
Automatically. Four design modes rank candidate pairs by penalty, each with Tm, GC%, hairpin, self-dimer and heterodimer checks:
| Mode | For |
|---|---|
| General | The best pairs in the gene's exons, introns or anywhere, no other input: matched Tm, least hairpin/dimer structure |
| WGA | Whole-gene amplification from the flanking regions |
| Junction | cDNA-specific qRT-PCR primers across exon–exon junctions |
| SNP/indel | ARMS-PCR allele-specific primer sets |
|
|
One set of reaction conditions is used everywhere: design, analysis, structures and IDT. It matches IDT OligoAnalyzer's qPCR preset:
| Na⁺ | Mg²⁺ | dNTPs | Oligo |
|---|---|---|---|
| 50 mM | 3 mM | 0.8 mM | 0.2 µM |
- My primers gathers every set on the loaded sequence: WGA, general and junction pairs, the ARMS set and the probes. Each shows its amplicon size and Strider numbers, and has Show, Structures, IDT and Remove. Names are editable.
- Primer sets are remembered per sequence. Load the same gene and transcript again and they're back.
- Sessions: save everything to a
.primerool.jsonfile, load it later, or pick up an autosave.
- Paste FASTA, GenBank (a whole record or just its numbered sequence lines) or one bare sequence per line. You can also add the loaded sequence, or every other transcript variant of the gene, in one click.
- MAFFT aligns them. The result shows the classic way: a column ruler, one numbered row per sequence, a match line, mismatches highlighted and gaps dimmed.
- Collect homologs across species: give a gene and a taxon (e.g. nirS in Pseudomonas, or a taxonomy ID) and get one coding sequence per species, from GenBank proteins that record where they are coded.
- A conservation track and a list of conserved windows (adjustable identity threshold and length) show where primers can go.
- Design primers in a conserved window or a column range, as individual candidates, as pairs around a target, or as a pair across two windows. Every primer shows how many of the aligned sequences it matches, and how many would fail at its 3′ end.
→ primerool.ubch.sci.muni.cz. Nothing to install.
Prerequisites
| Tool | Why |
|---|---|
| Rust (stable) | the server and the thermodynamics engines |
| A C compiler (tests only) | builds the vendored Primer3 used as a reference in cargo test --workspace |
| Node.js 20.19+ | the frontend (Vite 7) |
| MAFFT (optional) | multi-sequence alignment |
git clone --recurse-submodules https://github.com/KowalskiBio/Primerool.git
cd Primerool
npm run setup # cargo build (minus the Primer3 reference crates) + frontend npm install
npm run dev # Rust API on :5050 + Vite on :5173, with hot reloadThen open http://localhost:5173.
The Tauri shell in src-tauri/ runs the same server in-process and opens it in a native window:
cargo install tauri-cli
cargo tauri build # builds the frontend first, then the native appflowchart LR
A["🔎 Gene name<br/>accession · sequence"] --> B["📥 Ensembl / NCBI<br/>transcripts, exons, flanks"]
B --> C["🗺️ Sequence, feature<br/>& exon maps"]
C --> D["🖱️ Right-click picks<br/>drag to move / resize"]
C --> E["⚙️ Automatic design<br/>General · WGA · Junction · SNP"]
D --> F["🌡️ Strider<br/>Tm · GC · hairpins · dimers"]
E --> F
F --> G["🧾 My primers<br/>BLAST · structures · IDT"]
The backend is a Rust workspace with one job per crate, and the frontend is a React single-page app. In production, one axum binary serves both the API and the built frontend.
flowchart TB
UI["React 19 · TypeScript · Tailwind 4<br/><code>frontend/</code>"] -->|JSON over HTTP| S["axum server<br/><code>crates/server</code>"]
T["Tauri desktop shell<br/><code>src-tauri/</code>"] -.->|runs in-process| S
S --> E["engine<br/>design · scoring"]
E --> TC["thermo-core<br/>Strider thermodynamics"]
S --> PR["providers<br/>Ensembl · NCBI"]
S --> BL["blast<br/>NCBI BLAST"]
S --> AL["align<br/>MAFFT"]
S --> ID["idt<br/>OligoAnalyzer proxy"]
S --> SN["snp-import<br/>.docx SNP reports"]
| Crate | Role |
|---|---|
server |
axum HTTP/JSON API: routing, validation and response shaping only |
engine |
Design modes plus the Strider picker: candidate scan / filter / score / rank |
thermo-core |
Strider: plain-Rust Tm, salt corrections, hairpin/dimer ΔG, Mathews 2004 folding |
primer3-ffi · primer3-sys |
Test-only: bindings to the vendored Primer3, used to compare Strider against it (ADR 0001) |
providers |
SequenceProvider trait with Ensembl and NCBI implementations |
blast |
NCBI BLAST: submit, poll, fetch, parse |
align |
MAFFT subprocess wrapper |
idt |
IDT OligoAnalyzer OAuth2 proxy; credentials are per-request and never stored |
snp-import |
Parses per-SNP flanking-sequence .docx reports |
Repository layout
Primerool/
├── crates/ Rust workspace: server, engine, thermo-core, providers, …
├── frontend/ React + TypeScript + Tailwind single-page app (Vite)
├── src-tauri/ Tauri desktop shell
├── vendor/primer3-py/ Primer3 C sources (git submodule, test reference only)
├── scripts/ setup, dev runner, VM deploy, golden fixtures
├── docs/adr/ architecture decision records
└── docs/images/ README screenshots
cargo test --workspace # Rust unit + parity tests
cargo test -p server --test golden -- --ignored # replay live API fixtures (network)
npm --prefix frontend run lint # ESLint
npm --prefix frontend run build # type-check + production buildThe golden fixtures in scripts/golden/fixtures pin the API's responses, so behaviour stays stable across refactors.
Deploying to a server: scripts/deploy_vm.sh fast-forwards the checked-out branch, builds the release server and the frontend, backs up the live install, restarts the systemd service, health-checks it, and rolls back automatically if the check fails.
Primerool stands on the shoulders of MAFFT, the Ensembl REST API, NCBI E-utilities and BLAST, and IDT OligoAnalyzer. Nearest-neighbour parameters follow SantaLucia & Hicks (2004); folding energies follow Mathews et al. (2004). Primer3 (via primer3-py) set the defaults Strider's picker follows and serves as the reference in its tests.
Copyright (C) 2026 Vojtech Rejtar.
Primerool is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). If you modify it and let others use it, including over a network, you must publish your modified source under the same license and keep the original copyright and attribution notices.
Third-party code keeps its own license: crates/thermo-core is derived from Strider (MIT, Copyright (c) 2026 Emilio Venegas), and the vendored Primer3 in vendor/primer3-py is GPL-2.0-or-later.
Made for the bench by Vojtěch Rejtar · primerool.ubch.sci.muni.cz