EMILUA(7)
β¨ NAME β¨
okay bestie, welcome to EMILUA(7) β the manual page for Emilua, the Lua execution engine. Yes, this is the whole vibe, and weβre getting into it. π
π DESCRIPTION π
Emilua has its own module system. It may look familiar, and honestly that is literally the intention. Given the fact that other libraries out in the wild will have incompatible execution models, compatibility with existing lua libraries is not a concern (although it is most likely to just work for libraries w/o advanced needs). π«Ά
The module system is highly inspired by the Rust packaging system. The two languages, however, are too different, and these differences impact the module system as well. To import a module in dynamic languages such as lua, Python, and JavaScript, it is to evaluate/execute source code. Rust doesnβt have this constraint and Rust gets just fine with a lot of static analysis. The two languages live in separate worlds. Finally, the module system is also inspired by what Python and NodeJS do. π
A module system is meant to isolate pieces of code, symbols, and names. Modules shouldnβt interfere with each other. And a module can have dependencies on other modules to reuse code. So, there is the need for private members and exported members. Lua has all the features we need β closures, nested scopes, environments, global scope as a table β to implement a module system easily. π
π QUICK-START π
The things you need to know to get started, bestie:
require()is a free function receiving a string with the module id and returning the module. Two imports to the same module will only evaluate it once. The result is cached per running VM instance. β¨- Every file you write is a module.
- Global names will be exported for modules that import your module.
- Modules can also be directories. In this case, a file named
init.luawill be searched and imported in that directory.init.luacan import any other module inside its directory. - π¨ Cyclic references are unsupported and will raise an error on import.
- You can use the syntax
require('../foobar')to import a sibling module namedfoobar. - If the module id doesnβt start with
'./'or'../'then it is assumed to refer to an external package and different rules apply (see section at the end).
πΈ Small example πΈ
File src/init.lua:
local server = require('./server')
local hostname = '127.0.0.1'
local port = 3000
local s = server.new(function(sock, req, res)
res.headers = {
['content-type'] = 'text/plain'
}
res.body = 'Hello World\n'
sock:write_response(res)
end)
s:listen(hostname, port)
File src/server.lua:
local ip = require('ip')
local http = require('http')
local mt = {}
mt.__index = mt
function new(handler)
return setmetatable({ handler = handler }, mt)
end
function mt:listen(hostname, port)
local acceptor = ip.tcp.acceptor.new()
acceptor:open(ip.address.new(hostname))
acceptor:bind(hostname, port)
acceptor:listen()
spawn(function()
while true do
local s = http.socket.new(acceptor:accept())
spawn(function()
local req = http.request.new()
local res = http.response.new()
while true do
s:read_request(req)
res.status = 200
res.reason = 'OK'
res.headers = nil
res.body = nil
res.trailers = nil
self.handler(s, req, res)
end
end)
end
end):detach()
end
π BIG MODULES π
A typical project structure may look as follows:
src
βββ init.lua
βββ my_module
β βββ error.lua
β βββ init.lua
β βββ util.lua
β βββ worker.lua
βββ util.lua
In this example, there is the project scope whose root begins at src/init.lua β the root module. π
In the root module, it is forbidden to use require('../') statements as there is no parent module. Any name the src/init.lua file require()s will be searched on the src directory. For instance, if src/init.lua contains require('./util'), emilua will use the src/util.lua file to define the importing module. π¦
But modules may grow and can be further split into files within a directory by itself. That was the case for my_module. The init.lua file in that directory will be searched for, and, once found, evaluated. If src/my_module/init.lua contains more require() calls whose arguments start with './', files within that directory (src/my_module) will be searched for. π
For instance, if src/my_module/init.lua contains require('./worker'), the file src/my_module/worker.lua will be searched for. Any file (except for init.lua) within src/my_module can import other files from the same directory (i.e. their siblings) using the require('../') form (src/my_module/init.lua siblings live in the directory above, src). For instance, src/my_module/worker.lua and src/my_module/util.lua may both want to use the same error type (possibly private) to that module β src/my_module/error.lua. In this case, all they need to contain is the call require('../error'). And finally due to how they are defined by files (not directories by themselves), they donβt have children modules and canβt use the usual require('./') call (i.e. the call argument must start with ../). π
Any number of super levels is allowed (e.g. require('../../../../foobar')). No cap, bestie. π
π¦ EXTERNAL PACKAGES π¦
If the module name to import doesnβt begin with './' nor '../' then itβll be searched for outside of the project directory. The places Emilua will look for are:
- Core modules (e.g.
'inbox'). - External packages.
Emilua looks for external packages by examining the following locations (in that order):
- The
EMILUA_PATHenvironment variable. Thatβs a colon-separated list[1] of directories. - The installation-dependent default (usually
$PREFIX/lib/emilua-$VERSION).
π MISC π
You might be interested in restricting the filenames of your modules to the set discovered by Boost developers over the years:
π NOTES π
[1] Itβs semicolon-separated on Windows. πͺ
π Thatβs the whole vibe for EMILUA(7) β source/version Emilua 0.12.1-nixpkgs1, dated 1980-01-01. Go build something iconic, bestie. π
β¨
π¦ where this page comes from
- nixos 26.05: emilua 0.12.1
- nixpkgs unstable: emilua 0.12.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms