omniLua

Every Lua,
everywhere.

omniLua is a Lua interpreter written in pure, safe Rust. One codebase runs Lua 5.1 through 5.5 with no C dependency — on the command line, embedded in a Rust program, or in the browser and Node.

$ cargo install omnilua-cli

It passes the official PUC-Rio test suites, runs the stock LuaRocks client, and keeps unsafe out of everything but the garbage collector.

$ omnilua -e 'print(6 * 7)'
  42

Try it — one snippet, five Luas

edit the code and run it live on every version; the output diverges
snippet.lua ⌘ / Ctrl + Enter

live — your code on each version's backend ref — reference output, shown until the runtime loads

§ 01

Capabilities

It's one runtime underneath: the same code runs Lua 5.1 through 5.5, chosen at startup, and builds either natively or to wasm32 from a single source.

i.

Standalone

the omnilua interpreter

A drop-in lua for files, one-liners, and the REPL. Pick a version with OMNILUA_VERSION.

$ omnilua script.lua
ii.

Embedded

the omnilua crate

An mlua-shaped API in pure Rust, with no liblua and no C toolchain. Borrow host state with scope, or sandbox untrusted scripts.

# omnilua = "0.2"
iii.

Browser

npm · wasm

The whole runtime as a single .wasm — Lua in the page, with no Emscripten and no bundled interpreter.

$ npm install omnilua
iv.

Node

same package, server-side

The same .wasm on the server, with no node-gyp and no native build. It runs anywhere JavaScript does.

import "omnilua/node"

Pure Rust, so it compiles to wasm. Ship a game or app to the browser and the scripting layer comes with it — a C-backed Lua binding can't. — a Bevy demo drives an entity from Lua each frame and builds to wasm32, in the repository.

Conformance you can check5.4 passes the full upstream PUC-Rio suite; ./harness/run_official_all.sh reports the live count against the unmodified tests.
SandboxingUntrusted scripts get uncatchable CPU and memory caps with host access stripped — Lua::sandboxed(SandboxConfig::strict()), refillable per run.
Scoped borrowsLua::scope lends a non-'static borrow (a game engine's &mut World) for one call; an escaped handle errors cleanly instead of dangling.
LuaRocksRuns the stock LuaRocks 3.11.1 client and installs pure-Lua rocks — inspect, dkjson, argparse, middleclass, say, luassert.
Memory safety, measuredZero unsafe outside the GC, the dylib loader, and the wasm ABI. The safety tax is measured at ~0%, not assumed.
One core, five versionsFloat-only 5.1/5.2 through integer-aware 5.3/5.4/5.5 — one dispatch loop, chosen at runtime.
Supported versions — verified against the reference, per version
VersionStatusVerified against
5.4stable · productionFull upstream PUC-Rio suite
5.3 / 5.5beta · long tails closedTheir own upstream test trees + reference binary
5.1 / 5.2supportedBehavioral battery + upstream example programs

This is Lua source/runtime compatibility, not C API/ABI compatibility. 5.1/5.2 are float-only number families; math.random sequences differ from C (host PRNG). Native C rocks are not supported in LuaRocks yet — pure-Lua rocks are.

§ 02

Performance

Competitive with reference C, not faster, not LuaJIT. Numbers tracked per-commit; the cost of safety is measured.

1.37×
wall-time geomean
vs reference C (stock)
0.42×
fastest workload
2.4× faster than C
~0%
safety tax
bounds checks + guards
1.72×
peak memory geomean
vs reference C

The gap to C is representation, not safety. Bounds checks and RefCell guards cost ~0% of wall time; three workloads already beat C outright.

§ 03

Get omniLua

Rust CLI
$ cargo install omnilua-cli
Embed in Rust
# Cargo.toml
omnilua = "0.2"
Browser / Node
$ npm install omnilua
embedding — shaped after mlua
use omnilua::Lua;

let lua = Lua::new();
let f = lua.create_function(|_, name: String| Ok(format!("hello, {name}")))?;
lua.globals().set("greet", f)?;
lua.load(r#"print(greet("omniLua"))"#).exec()?;
// → hello, omniLua

Full API on docs.rs · the browser/Node package wrapper, with a runnable example, on npm.