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.
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)'
use omnilua::Lua; let lua = Lua::new(); lua.load("print(6 * 7)").exec()?;
import { loadLuaRs, luaRsWasmUrl } from "omnilua"; const { lua } = await loadLuaRs(luaRsWasmUrl); lua.exec("print(6 * 7)");
import { loadLuaRsNode } from "omnilua/node"; const { lua } = await loadLuaRsNode(); lua.exec("print(6 * 7)");
Try it — one snippet, five Luas
edit the code and run it live on every version; the output divergeslive — your code on each version's backend ref — reference output, shown until the runtime loads
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.
Standalone
A drop-in lua for files, one-liners, and the REPL. Pick a version with OMNILUA_VERSION.
Embedded
An mlua-shaped API in pure Rust, with no liblua and no C toolchain. Borrow host state with scope, or sandbox untrusted scripts.
Browser
The whole runtime as a single .wasm — Lua in the page, with no Emscripten and no bundled interpreter.
Node
The same .wasm on the server, with no node-gyp and no native build. It runs anywhere JavaScript does.
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.
./harness/run_official_all.sh reports the live count against the unmodified tests.Lua::sandboxed(SandboxConfig::strict()), refillable per run.Lua::scope lends a non-'static borrow (a game engine's &mut World) for one call; an escaped handle errors cleanly instead of dangling.inspect, dkjson, argparse, middleclass, say, luassert.unsafe outside the GC, the dylib loader, and the wasm ABI. The safety tax is measured at ~0%, not assumed.| Version | Status | Verified against |
|---|---|---|
| 5.4 | stable · production | Full upstream PUC-Rio suite |
| 5.3 / 5.5 | beta · long tails closed | Their own upstream test trees + reference binary |
| 5.1 / 5.2 | supported | Behavioral 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.
Performance
Competitive with reference C, not faster, not LuaJIT. Numbers tracked per-commit; the cost of safety is measured.
vs reference C (stock)
2.4× faster than C
bounds checks + guards
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.
Get omniLua
$ cargo install omnilua-cli
# Cargo.toml
omnilua = "0.2"
$ npm install omnilua
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.