SkillAgentSearch skills...

Mlua

High level Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau bindings to Rust with async/await support

Install / Use

/learn @mlua-rs/Mlua
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

mlua

Build Status Latest Version API Documentation Coverage Status MSRV

Guided Tour | Benchmarks | FAQ

The main branch is the development version of mlua. Please see the v0.11 branch for the stable versions of mlua.

mlua is a set of bindings to the Lua programming language for Rust with a goal of providing a safe (as much as possible), high level, easy to use, practical and flexible API.

Started as an rlua fork, mlua supports Lua 5.5, 5.4, 5.3, 5.2, 5.1 (including LuaJIT) and Luau and allows writing native Lua modules in Rust as well as using Lua in a standalone mode.

mlua is tested on Windows/macOS/Linux including module mode in GitHub Actions on x86_64 platforms and cross-compilation to aarch64 (other targets are also supported).

WebAssembly (WASM) is supported through the wasm32-unknown-emscripten target for all Lua/Luau versions excluding JIT.

Usage

Feature flags

mlua uses feature flags to reduce the number of dependencies and compiled code, and allow choosing only the required set of features. Below is a list of the available feature flags. By default mlua does not enable any features.

  • lua55: enable Lua 5.5 support
  • lua54: enable Lua 5.4 support
  • lua53: enable Lua 5.3 support
  • lua52: enable Lua 5.2 support
  • lua51: enable Lua 5.1 support
  • luajit: enable LuaJIT support
  • luajit52: enable LuaJIT support with partial compatibility with Lua 5.2
  • luau: enable Luau support (auto vendored mode)
  • luau-jit: enable Luau support with JIT backend.
  • luau-vector4: enable Luau support with 4-dimensional vector.
  • vendored: build static Lua(JIT) libraries from sources during mlua compilation using lua-src or luajit-src
  • module: enable module mode (building loadable cdylib library for Lua)
  • async: enable async/await support (any executor can be used, eg. tokio or async-std)
  • send: make mlua::Lua: Send + Sync (adds Send requirement to mlua::Function and mlua::UserData)
  • error-send: make mlua:Error: Send + Sync
  • serde: add serialization and deserialization support to mlua types using serde
  • macros: enable procedural macros (such as chunk!)
  • anyhow: enable anyhow::Error conversion into Lua
  • userdata-wrappers: opt into impl UserData for Rc<T>/Arc<T>/Rc<RefCell<T>>/Arc<Mutex<T>> where T: UserData

Async/await support

mlua supports async/await for all Lua versions including Luau.

This works using Lua coroutines and requires running Thread along with enabling feature = "async" in Cargo.toml.

Examples:

shell command examples:

# async http client (hyper)
cargo run --example async_http_client --features=lua54,async,macros

# async http client (reqwest)
cargo run --example async_http_reqwest --features=lua54,async,macros,serde

# async http server
cargo run --example async_http_server --features=lua54,async,macros,send
curl -v http://localhost:3000

Serde support

With the serde feature flag enabled, mlua allows you to serialize/deserialize any type that implements serde::Serialize and serde::Deserialize into/from mlua::Value. In addition, mlua provides the serde::Serialize trait implementation for mlua::Value (including UserData support).

Example

Compiling

You have to enable one of the features: lua54, lua53, lua52, lua51, luajit(52) or luau, according to the chosen Lua version.

By default mlua uses pkg-config to find Lua includes and libraries for the chosen Lua version. In most cases it works as desired, although sometimes it may be preferable to use a custom Lua library. To achieve this, mlua supports the LUA_LIB, LUA_LIB_NAME and LUA_LINK environment variables. LUA_LINK is optional and may be dylib (a dynamic library) or static (a static library, .a archive).

An example of how to use them:

my_project $ LUA_LIB=$HOME/tmp/lua-5.2.4/src LUA_LIB_NAME=lua LUA_LINK=static cargo build

mlua also supports vendored Lua/LuaJIT using the auxiliary crates lua-src and luajit-src. Just enable the vendored feature and cargo will automatically build and link the specified Lua/LuaJIT version. This is the easiest way to get started with mlua.

Standalone mode

In standalone mode, mlua allows adding scripting support to your application with a gently configured Lua runtime to ensure safety and soundness.

Add to Cargo.toml:

[dependencies]
mlua = { version = "0.11", features = ["lua54", "vendored"] }

main.rs

use mlua::prelude::*;

fn main() -> LuaResult<()> {
    let lua = Lua::new();

    let map_table = lua.create_table()?;
    map_table.set(1, "one")?;
    map_table.set("two", 2)?;

    lua.globals().set("map_table", map_table)?;

    lua.load("for k,v in pairs(map_table) do print(k,v) end").exec()?;

    Ok(())
}

Module mode

In module mode, mlua allows creating a compiled Lua module that can be loaded from Lua code using require. In this case mlua uses an external Lua runtime which could lead to potential unsafety due to the unpredictability of the Lua environment and usage of libraries such as debug.

Example

Add to Cargo.toml:

[lib]
crate-type = ["cdylib"]

[dependencies]
mlua = { version = "0.11", features = ["lua54", "module"] }

lib.rs:

use mlua::prelude::*;

fn hello(_: &Lua, name: String) -> LuaResult<()> {
    println!("hello, {}!", name);
    Ok(())
}

#[mlua::lua_module]
fn my_module(lua: &Lua) -> LuaResult<LuaTable> {
    let exports = lua.create_table()?;
    exports.set("hello", lua.create_function(hello)?)?;
    Ok(exports)
}

And then (macOS example):

$ cargo rustc -- -C link-arg=-undefined -C link-arg=dynamic_lookup
$ ln -s ./target/debug/libmy_module.dylib ./my_module.so
$ lua5.4 -e 'require("my_module").hello("world")'
hello, world!

On macOS, you need to set additional linker arguments. One option is to compile with cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup, the other is to create a .cargo/config.toml with the following content:

[target.x86_64-apple-darwin]
rustflags = [
  "-C", "link-arg=-undefined",
  "-C", "link-arg=dynamic_lookup",
]

[target.aarch64-apple-darwin]
rustflags = [
  "-C", "link-arg=-undefined",
  "-C", "link-arg=dynamic_lookup",
]

On Linux you can build modules normally with cargo build --release.

On Windows the target module will be linked with the lua5x.dll library (depending on your feature flags). Your main application should provide this library.

Module builds don't require Lua binaries or headers to be installed on the system.

Publishing to luarocks.org

There is a LuaRocks build backend for mlua modules: luarocks-build-rust-mlua.

Modules written in Rust and published to luarocks:

Safety

One of mlua's goals is to provide a safe API between Rust and Lua. Every place where the Lua C API may trigger an error longjmp is protected by lua_pcall, and the user of the library is protected from directly interacting with unsafe things like the Lua stack. There is overhead associated with this safety.

Unfortunately, mlua does not provide absolute safety even without using unsafe . This library contains a huge amount of unsafe code. There are almost certainly bugs still lurking in

Related Skills

View on GitHub
GitHub Stars2.6k
CategoryCustomer
Updated1d ago
Forks197

Languages

Rust

Security Score

85/100

Audited on Mar 22, 2026

No findings