Modules and require
Prerequisites: Object-oriented programming
A module is a file that returns a table of functions. require loads
it.
-- illustrative
-- mathutils.lua
local M = {}
local function check(n) -- private: not in M
assert(type(n) == "number", "expected a number")
end
function M.square(n)
check(n)
return n * n
end
function M.clamp(n, low, high)
return math.max(low, math.min(high, n))
end
return M
-- illustrative
-- main.lua
local mathutils = require("mathutils")
print(mathutils.square(7))
print(mathutils.clamp(150, 0, 100))
Here are both files in one runnable example (the first lines write
mathutils.lua to disk):
local f = assert(io.open("mathutils.lua", "w"))
f:write([[
local M = {}
local loads = 0
loads = loads + 1
print("loading mathutils")
function M.square(n) return n * n end
function M.clamp(n, low, high) return math.max(low, math.min(high, n)) end
return M
]])
f:close()
local mathutils = require("mathutils")
print(mathutils.square(7))
print(mathutils.clamp(150, 0, 100))
local again = require("mathutils")
print(again == mathutils)
loading mathutils
49
100
true
require("mathutils")findsmathutils.lua, runs it once, and caches the returned table inpackage.loaded. Laterrequirecalls return the same table — "loading mathutils" printed only once.- Locals in the module file (like
check) are private. - Assign the result to a local — modules shouldn't create globals.
Where require looks
require("a.b") replaces dots with directory separators and tries each
template in package.path:
for template in package.path:gmatch("[^;]+") do
if template:find("^%./") or template:find("^%.\\") then print(template) end
end
.\?.lua
.\?\init.lua
(This output is from Windows; on Linux and macOS the templates are
./?.lua and ./?/init.lua.) So require("utils.strings") loads
utils/strings.lua or utils/strings/init.lua from the current
folder, among other places. C libraries are found through
package.cpath. Hosts like Neovim and LÖVE add their own folders.
Module structure tips
- One module per file, returning a table (or a class).
- Keep module-level state minimal — it's shared by everything that requires the module.
- To reload a module during development, set
package.loaded["name"] = niland require it again.