From JavaScript

You have two ways in, and they run the same engine. You can write BioLang, which is shorter for pipelines and is what the rest of this documentation uses. Or you can stay in JavaScript entirely and call the runtime through the JavaScript SDK — your loops, your objects, your try/catch, with the sequence work and statistics happening in Rust either way.

This page shows the same computation both ways so you can decide per task. Every JavaScript snippet below was generated from the BioLang beside it and then executed and compared against it, so these are checked translations rather than plausible ones.

Key Differences at a Glance

Feature JavaScript BioLang
Bindings const / let let (immutable by default)
Chaining Method chains, or nested calls |> pipe, left to right
Anonymous functions (x) => x * 2 |x| x * 2
String interpolation `n=${n}` f"n={n}"
Biological types Strings, plus a library dna"ACGT", rna, protein are language types
Tables Arrays of objects, plus a library Table is built in, with filter, mutate, arrange
Numbers One number type Int and Float are distinct
Equality === with coercion rules to remember ==, no coercion

GC content

BioLang

gc_content(dna"ATCGATCGATCGATCG")
# 0.5

JavaScript

bl.gcContent(bl.dna("ATCGATCGATCGATCG"));
// 0.5

Builtin names are available in both spellings, so bl.gc_content(...) works too. Use whichever reads better in the surrounding code.

Filtering and transforming

BioLang

let xs = [1, 5, 12, 20]
xs |> filter(|x| x > 10) |> map(|x| x * 2) |> sum()
# 64

JavaScript

const xs = [1, 5, 12, 20];
bl.sum(bl.map(bl.filter(xs, (x) => x > 10), (x) => x * 2));
// 64

This is the one place the mapping is genuinely worse in JavaScript. A pipe reads left to right in the order the data flows; nested calls read inside out, so the first step is buried deepest. Ordinary JavaScript array methods are an option when the data is already in JavaScript — and for scalar loops they are also faster, because V8 beats a tree-walking interpreter. Reach for the BioLang builtins when the operation is one you would not want to reimplement.

Tables

BioLang

let t = table({gene: ["TP53", "BRCA1", "EGFR"], expr: [142.5, 87.3, 210.0]})
t |> filter(|r| r.expr > 100.0) |> nrow()
# 2

JavaScript

const t = bl.table({ gene: ["TP53", "BRCA1", "EGFR"], expr: [142.5, 87.3, 210.0] });
bl.nrow(bl.filter(t, (r) => r.expr > 100.0));
// 2

A plain JavaScript object of columns becomes a BioLang Table, and rows come back as objects whose fields you can read normally. Nothing needs to be reshaped by hand at the boundary.

Functions

BioLang

fn tm(primer) {
  return 64.9 + 41.0 * (gc_content(primer) - 0.164)
}

round(tm(dna"ACGTACGTACGT"), 2)

JavaScript

function tm(primer) {
  return 64.9 + 41.0 * (bl.gcContent(primer) - 0.164);
}

bl.round(tm(bl.dna("ACGTACGTACGT")), 2);

A BioLang function becomes a JavaScript function. Control flow stays yours: write if, for and try/catch the way you normally would, and call into BioLang for the parts that are worth calling into.

String interpolation

BioLang

let counts = [10, 12, 14, 11]
f"mean={mean(counts)}"

JavaScript

const counts = [10, 12, 14, 11];
`mean=${bl.mean(counts)}`;

Which should I write?

Write BioLang when the work is a pipeline — several stages of filter, map and summarise over sequences, reads or tables. That is what the pipe operator and the built-in biological types exist for, and the BioLang version is usually half the length.

Write JavaScript when BioLang is one step inside a larger program you already have: a web app, an API server, a notebook UI, an Electron shell. You keep your own tooling, debugger and error handling, and reach into the runtime for the bioinformatics.

You are not choosing once. bl.run(source) takes BioLang source from inside JavaScript, and bl.transpileJavaScript(source) converts an existing .bl file into the direct JavaScript API. Mixing the two in one program is normal.

Next

  • JavaScript SDK — sessions, values, handles, callbacks and what the build checks.
  • Verified equivalents — the same computation in BioLang, JavaScript, Python and R, each one executed and compared.
  • Embedding (WASM) — the raw module, if you do not want the package.
  • Pipes & operators — the part of BioLang with no JavaScript equivalent.