Barbell
Extremely fast and accurate Nanopore demultiplexing
Install / Use
/learn @rickbeeloo/BarbellREADME
🦀 Barbell — Pattern aware demux
Why Barbell?
- >1000× fewer trimming errors compared to Dorado.
- Equivalent or better assemblies.
- Contamination-free assemblies by removing artefact reads.
- Easily applicable to custom experiments.
- Still very fast.
If you have any issues or if something is unclear, just create an issue.
Quick links
- Installing barbell
- Quickstart
- In-depth inspection of Nanopore kit results
- Custom experiment
- Custom experiment with mixed sequences
- Output columns (annotate & filter)
- Patterns
- Paper evals
- Notes & tips
Paper
See the paper for more details on the Barbell scoring and comparisons with other tools:
Barbell Resolves Demultiplexing and Trimming Issues in Nanopore Data
Rick Beeloo, Ragnar Groot Koerkamp, Xiu Jia, Marian J. Broekhuizen-Stins, Lieke van Ijken, Bas E. Dutilh, Aldert L. Zomer
bioRxiv, 2025
https://doi.org/10.1101/2025.10.22.683865
Installing Barbell
Barbell is written in Rust.
Executables
Download the latest release from releases. These are also available via
cargo binstall barbell
or via conda/mamba/pixi:
conda install -c bioconda barbell
From source (recommended)
Check whether Rust is installed:
rustc --version
If not install it via rustup, more info in their
docs. Use rustup update to get the latest stable version.
Then we can install Barbell:
RUSTFLAGS="-C target-cpu=native" cargo install barbell
See here for
details on target-cpu=native.
📸 Preview
<img src="data/barbell_example.gif" alt="Demo GIF" width="700">Quickstart
Barbell includes built-in kit presets for many Nanopore kits (most DNA kits; RNA and Twist kits are an exception). Presets let you run analyses quickly, but we recommend reading Understanding barbell to interpret the results correctly.
Basic command:
barbell kit -k <kit-name> -i <reads.fastq> -o <output_folder> --maximize
The --maximize option is recommended (e.g., for assembly) unless you need an ultra-strict barcode configuration (see here for more details).
Native barcoding example (SQK-NBD114-96)
barbell kit -k SQK-NBD114-96 -i reads.fastq -o output_folder --maximize
This uses a conservative flank-based edit-distance cutoff. If many reads are missed during annotate, you can relax the flank error threshold, for example:
--flank-max-errors 5
—but always inspect the results after changing thresholds to avoid random matches (which show up as Fflank matches).
Rapid barcoding example (SQK-RBK114-96)
barbell kit -k SQK-RBK114-96 -i reads.fastq -o output_folder --maximize
For a list of supported kits (see data/supported_kits.txt). Note that we thoroughly tested the rapid and native kits but not others, if you experience any issues please report them.
Note, there is an option --use-extended which enables searches for fusion points, and other artefacts. This is around 3 times slower,
but worth it if quality is essential (i.e. generating consensus sequences).
General Pointers
-
Too few annotated reads (many missed):
Slightly increase--flank-max-errors(the automatically derived cutoff is reported). -
Too many
Fflankmatches:- Check
annotation.tsvto see if matches occur at unexpected locations (not near read ends).- Random locations: Lower
--flank-max-errors. - Non-random locations: Adjust
--min-score-diff.This is usually unnecessary as defaults are lenient; report an issue if it occurs.
- Random locations: Lower
- Check
-
Using a kit other than native or rapid and observing unexpected annotations: Please report an issue.
In-depth inspection of Nanopore kit results
Barbell's typical manual workflow: annotate → inspect → filter → trim.
Annotate
Run annotate to find matches in reads and output an annotation table (TSV):
barbell annotate --kit SQK-RBK114-96 -i pass_sample.fastq -t 10 -o anno.tsv
(Using 10 threads.)
Example anno.tsv rows:
read_id read_len rel_dist_to_end read_start_bar read_end_bar read_start_flank read_end_flank bar_start bar_end match_type flank_cost barcode_cost label strand cuts
c5f925b2-fc0b-4053-b615-d70950d41436 19783 14 14 104 14 104 0 0 Fflank 14 14 flank Fwd
dbca7fb9-d6c8-4417-8ae7-bc32ebce9b27 2972 29 48 70 29 111 0 23 Ftag 13 7 BC29 Fwd
6c089f0a-50cd-4215-94f0-c7babb87f5fe 7599 27 51 74 27 121 0 23 Ftag 11 5 BC45 Fwd
..etc
For column descriptions see Output columns (annotate & filter) below.
This file shows, per read, which barcodes/flanks were matched and with what costs. Use inspect next to summarize patterns.
Inspect
Summarize patterns across the annotation file:
barbell inspect -i anno.tsv
By default inspect shows the top 10 pattern groups; use -n <amount> to increase.
Example summary:
Found 64 unique patterns
Pattern 1: 82421 occurrences
Ftag[fw, *, @left(0..250)]
Pattern 2: 5003 occurrences
Ftag[fw, *, @left(0..250)]__Ftag[fw, *, @right(0..250)]
Pattern 3: 3545 occurrences
Fflank[fw, *, @left(0..250)]
...
Showed 10 / 64 patterns
Inspection complete!
Some observations:
Ftagon the left (@left) is the expected pattern for the rapid barcoding kit - that is good news.- A contamination pattern can be a barcode on the left and another barcode on the right (
@right). We can decide to just trim of the right side (see filtering later) Fflankindicates that flanks matched but no confident barcode was found.@prev_leftindicates additional tags close to a previous element (e.g., double-barcode ligation).
Per-read patterns
To output the selected pattern per read:
barbell inspect -i anno.tsv -o pattern_per_read.tsv
Example pattern_per_read.tsv contents:
85ef... \t Ftag[fw, *, @left(0..250)]
2f67... \t Ftag[fw, *, @left(0..250)]__Ftag[fw, *, @prev_left(0..250)]
...
This is useful when you want to inspect a single "weird" read in detail.
Filter
Create a filters.txt file listing the patterns you want to keep, one per line.
For example:
Ftag[fw, *, @left(0..250)]
Ftag[fw, *, @left(0..250)]__Ftag[fw, *, @right(0..250)]
Ftag[fw, *, @left(0..250)]__Ftag[fw, *, @prev_left(0..250)]
Then run:
barbell filter -i anno.tsv -f filters.txt -o filtered.tsv
The resulting filtered.tsv contains only reads that match the specified patterns.
Cutting / trimming metadata
Barbell needs to know where to cut reads for trimming. You mark cut positions by adding >> (cut after this element) or << (cut before this element) inside the tag's bracket list. Where within the brackets does not matter.
Examples (note the comma-separated fields inside the brackets):
Ftag[fw, *, @left(0..250), >>]
Ftag[fw, *, @left(0..250), >>]__Ftag[<<. fw, *, @right(0..250)]
Ftag[fw, *, @left(0..250)]__Ftag[fw, *, @prev_left(0..250), >>]
In the middle pattern we retain the read sequence between the left tag (cut after it) and the right tag (cut before it).
Run filter again (same command as above) to populate the cuts column in filtered.tsv. This is required before trimming.
Trim
Trim reads using the cuts metadata produced by filter:
barbell trim -i filtered.tsv -r reads.fastq -o trimmed
Output files are organized by pattern-based folder/filenames, for example:
BC14_fw__BC14_fw.trimmed.fastq BC31_fw__BC04_fw.trimmed.fastq ...
If you prefer different filename conventions, use these flags:
--no-label Disable label in output filenames
--no-orientation Disable orientation in output filenames
--no-flanks Disable flanks in output filenames
--sort-labels Sort barcode labels in output filenames
--only-side <left|right> Only keep left or right label in output filenames
Example to remove orientation and keep only the left label:
barbell trim -i filtered.tsv -r reads.fastq -o trimmed --no-orientation --only-side left
Gives:
BC01.trimmed.fastq BC11.trimmed.fastq ...
The --maximize flag explained in more detail (kit command only)
This flag affects the filter step. After locating barcodes/flanks, we use them to assign each read to a sample and
