A new language for fast, safe data science
Python's ease.
Rust's spine. R's data soul.
One language for scripting, systems, and data science — fast, safe, and 100% owned.
Vela is a statically-typed, compiled language — to native and WebAssembly — where the dataframe and the statistical formula are typed primitives. Code that feels dynamic but is checked before it runs: a typo'd column name fails at compile time, not at row 3 million.
# tokens, AST, and an evaluator — a compiler
# front-end written in Vela, running on Vela.
type Expr:
Num(n)
BinOp(op, a, b)
fn eval(e):
match e:
Num(n) => n
BinOp(op, a, b) =>
x = eval(a)
y = eval(b)
if op == "+": x + y
elif op == "*": x * y
else: x - y
print("2 + 3 * 4 =", calc("2 + 3 * 4"))
# -> 14 (precedence works)
The fusion
Three languages' best ideas, in one
Vela takes the readability of Python, the safety and speed of Rust, and the data-first heart of R — and makes them a single, coherent whole.
Readable & low-ceremony
Significant indentation, a gentle curve, expression-oriented syntax. You almost never write a type — inference fills them in.
- Clean, indentation-based layout
- REPL-first, "one language for everything"
- Pipelines (
|>) and lambdas read top-to-bottom
Safe, typed & fast
Strong static types with inference, algebraic types, exhaustive match, errors as values. Compiles native with a tiny runtime — no GC pauses.
- Type errors caught before runtime
Result/Optionand the?operator- Ownership & regions — opt-in, for hot paths
Data & stats, first-class
The Arrow-backed dataframe, the ~ formula, NA-as-a-type, and guaranteed-fusing vectorization live in the language — not bolted on as a library.
- Typed dataframes; columns referenced bare
- Broadcasting (
.*.+) that fuses to one loop - Built-in modeling:
lm, tests, distributions
Real Vela, running today
Code that feels dynamic, checks like static
Every snippet below runs on the Stage-0 seed interpreter. The semantics are final; the compiler in Phase 2 makes them fast.
Vectorized, element-wise math
Dot-operators broadcast a scalar across a vector. Chain them — sqrt, .^, .+ — and they read like math.
Pipelines and reductions flow left to right: xs |> sum.
# Vela's data soul: element-wise math
xs = [1.0, 2.0, 3.0, 4.0, 5.0]
# broadcast a scalar across a vector
print("xs .* 2 =", xs .* 2.0)
print("xs .+ 100 =", xs .+ 100.0)
# chained broadcast: z = sqrt(x^2 + 1)
z = sqrt.(xs .^ 2.0 .+ 1.0)
# pipelines + reductions, left to right
print("sum =", xs |> sum)
print("mean =", xs |> mean)
Algebraic types & pattern matching
Tagged unions (enums) plus exhaustive match — the foundation for Option, Result, and safe unwrapping with no null surprises.
Records are structural product types, accessed by field name. Together they model anything — a point, an AST node, a symbol table.
_ wildcard — the compiler will check that every case is handled.# records: structural product types
p = { x: 3, y: 4 }
print("x + y =", p.x + p.y)
# enums + match: a safe Option type
type Option:
Some(value)
None
fn unwrap_or(opt, fallback):
match opt:
Some(v) => v
None => fallback
print(unwrap_or(Some(42), 0)) # 42
print(unwrap_or(None, -1)) # -1
Typed dataframes & the ~ formula
The data-science workflow you know from R and pandas — filter → group_by → summarize — with columns referenced bare and the schema inferred.
Statistics are language citizens: the y ~ x1 + x2 formula desugars to a typed model-matrix builder feeding a built-in lm.
use std.data
use std.stats
# inferred: DataFrame<{region, amount: F64?, ...}>
df = read_csv("sales.csv")?
report =
df
|> filter(amount? > 0) # NA-aware
|> group_by(region)
|> summarize(total = sum(amount))
# formula syntax + built-in modeling
model = lm(chol ~ age + bmi, data = df)
print(summary(model)) # coefs, R², p-values
What's in the box
Built for fast, safe data science
Every pillar of the language serves one goal: make exploratory data work feel effortless, then make it production-fast and production-safe.
Static types + inference
Hindley–Milner-style local inference: you rarely write a type, yet everything is checked at compile time. Annotate public APIs; let scripts infer.
Tiered memory
Tier 0 is invisible: optimized reference counting, value semantics, no GC pauses, no borrow checker. Tier 1 adds ownership and regions when you want zero overhead.
Native + WebAssembly
One owned IR lowers to a tree-walking interpreter, native code, and WASM — in parallel. Run the same program on the desktop, the server, the edge, or the browser.
Owned toolchain
Our frontend, our IR, our backend, our runtime — 100% built by us. LLVM is optional, removable release scaffolding we own the right to evict.
First-class dataframes
The DataFrame<{…}> is an Arrow-backed, typed, extensible-row value — zero-copy to Polars, DuckDB, pandas, and R. Lazy plans, optimized by the compiler.
Fearless concurrency
Data-race freedom via ownership when you opt in; structured async, channels, and actors by default. The dataframe engine auto-parallelizes across cores for free.
The empty quadrant
Typed + compiled + data-native
Every existing language sits in a corner Vela deliberately leaves. We checked the field as of 2026 — the quadrant is genuinely unoccupied.
- R, pandas, Julia — brilliant with data, but dynamic, slow, or JIT-bound. No static checking.
- Rust, Go, Zig, Nim, Swift — static, fast, safe — but no first-class data or statistics story.
- Mojo — Python-ish + perf, but GPU-kernel-first, no native dataframe, core compiler proprietary, no WASM.
"Julia's numerics + Polars' engine + Rust's safety — where the dataframe and the formula are typed primitives, and the whole stack is owned."
Honest status
Where Vela is today
A real general-purpose language is a multi-year program — and we're at the start of it. Here's exactly what works now and what comes next. No vaporware.
Stage-0 seed interpreter Working today
A zero-dependency tree-walking interpreter in Rust runs real Vela: records, enums, match, pattern matching, string ops, and file I/O. A full calculator front-end — and a lexer — are already written in Vela, proving the self-hosting path.
Static types + inference Next
The typed HIR: Hindley–Milner local inference, algebraic types, traits, and the row-polymorphic record types that make typed dataframes possible. The typo'd-column-name compile error becomes real.
First-class dataframes & stats Phase 1
The Arrow-backed DataFrame<{…}>, filter/group_by/summarize, NA-as-a-type, the ~ formula → lm(), plus a REPL and Jupyter kernel. The end-to-end EDA script is the acceptance gate.
Own native + WASM backend Phase 2
Our own SSA-form MIR lowering to a native debug backend and a WebAssembly backend — in parallel, off one owned IR. Guaranteed broadcast fusion. Tier-1 ownership, borrowing, and regions arrive here. LLVM stays optional, for release-mode numerics only.
Self-hosting Phase 4
Rewrite the compiler in Vela and dogfood the language on itself, pinning the bootstrap to the previous release. Begin evicting LLVM toward our own optimizer. The destination: 100% owned, top to bottom.
Start exploring
Read the tutorial. Run the examples.
Vela is early and honest about it — but the seed works today, and the soul of the language is already here to try. Walk through the language guide, then read real .vela programs.