MquickjsEx - Embed JavaScript in Elixir without Node.js

I’ve just released MquickjsEx, an Elixir library for embedding JavaScript execution directly in your BEAM process using MQuickJS. It’s a new project that got a huge attention on hackernews.

Why?

I built this to let LLMs execute JavaScript code securely with minimal overhead. When an LLM generates JS code for data transformation or custom logic, I wanted to run it in a sandbox where I control exactly what functions are available - no filesystem, no network, just the tools I expose.

I will be also experimenting if it would be possible to create a very fast Server Side Renderer for my other library, LiveVue.

What is it?

MquickjsEx wraps MQuickJS (Fabrice Bellard’s minimal JS engine) via NIFs. Similar to what pythonx does for Python, but the API is inspired by tv-labs/lua.

Key points:

  • No external runtime - no Node.js, Bun, or Deno installation
  • In-process - runs inside the BEAM via NIFs, no subprocess spawning
  • Tiny footprint - MQuickJS can run in as little as 10KB RAM (default 64KB)
  • Sandboxed - no filesystem or network access by default
  • Bidirectional - call JS from Elixir and Elixir from JS

Usage

# Create context and evaluate code
{:ok, ctx} = MquickjsEx.new()
{:ok, 3} = MquickjsEx.eval(ctx, "1 + 2")

# Expose Elixir functions to JavaScript
ctx = MquickjsEx.set!(ctx, :fetch_data, fn [table] -> MyApp.Repo.all(table) end)
{result, _ctx} = MquickjsEx.eval!(ctx, "fetch_data('users').length")

# Define reusable API modules
defmodule MathAPI do
  use MquickjsEx.API, scope: "math"
  defjs add(a, b), do: a + b
end

{:ok, ctx} = MquickjsEx.new()
{:ok, ctx} = MquickjsEx.load_api(ctx, MathAPI)
{:ok, 5} = MquickjsEx.eval(ctx, "math.add(2, 3)")

Important Limitations

MQuickJS implements a subset of JavaScript close to ES5 with a stricter mode. You need to know these:

Arrays cannot have holes:

a = []
a[10] = 1;  // TypeError - can only extend at end
[1, , 3]    // SyntaxError

No direct eval:

eval('1 + 2');       // Forbidden
(1, eval)('1 + 2');  // OK (indirect eval)

No value boxing:

new Number(1)  // Not supported

Limited Date support:
Only Date.now() works.

ASCII-only for some string ops:
toLowerCase() / toUpperCase() only handle ASCII.

Re-execution pattern for callbacks:
When JS calls an Elixir function, execution pauses, Elixir runs the callback, then JS re-executes from the start with cached results. This means your JS code should be idempotent - no side effects that accumulate on replay.

Installation

def deps do
  [{:mquickjs_ex, "~> 0.1.0"}]
end

Full docs and more examples: GitHub - Valian/mquickjs_ex: Embedded JS runtime for Elixir based on MQuickJS · GitHub.

I need to disclose, it was created by collaborating closely with Claude Code Opus 4.5, otherwise it would be not possible.

Feedback welcome - this is the first release. Hope you’ll like it!

https://github.com/Valian/mquickjs_ex

8 Likes