# Lua modules on MediaWiki: Scribunto, #invoke and safe testing

> Lua modules power advanced MediaWiki templates through Scribunto. How #invoke works, a first module, the debug console, unit tests and Scribunto on your wiki.

Canonical: https://xyrael.net/lua-modules-scribunto
Updated: 2026-10-31

Lua modules are scripts kept in a wiki's Module namespace and run by the Scribunto extension; a page calls one with {{#invoke:Module|function}}. The English Wikipedia has used them since February 2013, and Scribunto, which runs Lua 5.1, comes bundled with MediaWiki.

## How #invoke calls a module

A module is a container of functions and does nothing by itself, so every call names one function: *{{#invoke:Example|hello}}* runs the function *hello* in *Module:Example*. Text after the first pipe is always the function name; the module's own arguments start after the second pipe and work like template parameters, positional or named.

- *{{#invoke:Example|hello}}* — no arguments.
- *{{#invoke:Example|hello_to|Kate}}* — one positional argument.
- *{{#invoke:Example|count_fruit|apples=3|bananas=4}}* — named arguments, in any order.

Scribunto's manual recommends calling a module through a template rather than directly, so editors keep the familiar template syntax whether the logic inside is wikitext or Lua. The VisualEditor cannot insert an #invoke itself; on the English Wikipedia the wrapper template {{invoke}} does the same job there.

## Your first module, line by line

Scribunto's manual starts with a module of five lines. Create a page such as *Module:Bananas* (on Wikipedia, a subpage of *Module:Sandbox*) containing:

1. *local p = {}* — a table that will hold the functions pages may call.
2. *function p.hello( frame )* — adds a function named *hello* to that table.
3. *return "Hello, world!"* — what the function sends back to the page.
4. *end* — closes the function.
5. *return p* — every module must end by returning its table.

Save it, then write *{{#invoke:Bananas|hello}}* on an ordinary page: the call is replaced by *Hello, world!*. Functions left out of the returned table cannot be called from a page, and the manual advises declaring everything *local*.

Arguments arrive in the *frame* object: *frame.args* holds those given to #invoke, and *frame:getParent().args* holds those given to the template that contains the call, which is how most real modules read their parameters.

## Testing a module safely

- **The debug console.** Under the edit form of every module is a console that runs Lua without saving, or even creating, the module.
- **Sandboxes.** On the English Wikipedia, subpages of *Module:Sandbox* and *Module:User:YourName/…* serve as module sandboxes, the way user subpages do for articles.
- **Unit tests.** By convention the tests for *Module:Example* live at *Module:Example/testcases* and run on its talk page with *{{#invoke:Example/testcases|run_tests}}*. *Module:UnitTests* is the default framework; *Module:ScribuntoUnit* is the other common one.
- **Script errors.** A red *Script error* message on a page is clickable and opens more detail about what went wrong.

Change a module used by a template the same way you would change the template: copy it to a sandbox, test, then copy back. The method is on [template sandboxes and test cases](/template-sandbox-testcases).

## How Scribunto's Lua differs from ordinary Lua

- **Lua 5.1 only**, with some functions changed or removed: there is no access to files or C libraries, and *require()* loads only Scribunto's built-in libraries and other modules on the wiki, by full page name.
- **Each #invoke runs in its own environment**, so variables set in one call are gone in the next.
- **Input comes from page text.** A module runs when a page is parsed, so it cannot react to a reader's clicks or typing.
- **Output is not re-parsed.** Templates or parser functions in a module's return value stay as plain text unless the module calls *frame:preprocess()*.
- **Time is limited.** On Wikipedia all the Lua on one page shares a limit of 10 seconds of processor time.

## Running Lua modules on your own wiki

Scribunto has been bundled with MediaWiki since version 1.34, so a fresh [MediaWiki installation](/install-mediawiki) only needs it switched on in *LocalSettings.php*: *wfLoadExtension( 'Scribunto' );* followed by *$wgScribuntoDefaultEngine = 'luastandalone';*.

- **Requirements.** PHP needs the mbstring extension and PCRE 8.33 or newer.
- **The Lua binary.** Scribunto ships Lua binaries for Linux (x86 and x86-64), Mac OS X Lion and Windows (32- and 64-bit). Other systems need a Lua 5.1 binary from LuaBinaries or the distribution, set with *$wgScribuntoEngineConf['luastandalone']['luaPath']*.
- **Permissions.** If modules fail with an error about the Lua binary, make it executable (*chmod a+x* on the binary in Scribunto's *LuaStandalone/binaries* folder).
- **Speed.** The LuaSandbox PHP extension runs Lua inside PHP, faster than the standalone binary; after installing it, set the engine to *'luasandbox'*.

## How Lua reached Wikipedia

Before Lua, complex templates were built from wikitext tricks and, later, ParserFunctions. After years of debate over a scripting language, Scribunto was written with Lua support; it was installed on test2.wikipedia.org in 2012 with an open invitation to every editor, then on the English Wikipedia in February 2013 after testing on mediawiki.org and the Wikimedia test wikis. More about those wikis is on [Test Wikipedia](/test-wikipedia).

## Frequently asked questions

### What is Scribunto?

The MediaWiki extension that lets wikis run Lua scripts, called modules, from the Module namespace. It has been bundled with MediaWiki since version 1.34.

### Which version of Lua does Wikipedia use?

Lua 5.1, run by Scribunto, with some standard functions changed or removed for safety.

### Can I test Lua without saving a module?

Yes. The debug console under a module's edit form runs code without saving or creating the module.

### Where should I practise writing modules on Wikipedia?

On a subpage of Module:Sandbox, or on your own wiki with Scribunto enabled, where nothing you break affects other pages.
