Lua Modules Guide — require, Module Patterns, and Package Organization
In this tutorial, you will learn about Lua Modules Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Lua modules are tables returned from separate files, loaded with require() and cached in package.loaded to provide code organization, namespace management, and dependency control.
What You'll Learn
- Creating and using modules with require
- Module patterns: table return, local scope
- The package system and search paths
- Managing dependencies with LuaRocks
Why It Matters
Modules are essential for organizing Lua code beyond single-file scripts. Durga Antivirus Pro uses Lua modules to separate threat detection rules, configuration logic, and reporting into maintainable units. Games use modules to organize entities, systems, and utilities.
-- math_utils.lua (module file)
local math_utils = {}
function math_utils.add(a, b)
return a + b
end
function math_utils.multiply(a, b)
return a * b
end
return math_utils
-- main.lua (uses the module)
local math = require("math_utils")
print(math.add(5, 3)) --> 8
print(math.multiply(4, 2)) --> 8
Using require
require loads a module once and returns it. Subsequent calls return the cached value.
-- require looks for files in package.path
local my_module = require("my_module")
-- Lua searches: my_module.lua, my_module/init.lua in package.path
-- Module caching
local a = require("my_module")
local b = require("my_module")
print(a == b) --> true (same table)
Package Search Path
-- Default search paths
print(package.path)
-- ./?.lua;./?/init.lua;/usr/local/share/lua/5.4/?.lua;...
-- Add custom path
package.path = package.path .. ";/home/me/mylibs/?.lua"
-- For C libraries
print(package.cpath)
-- ./?.so;/usr/local/lib/lua/5.4/?.so;...
Module Patterns
Pattern 1: Table Return (Recommended)
-- greet.lua
local greet = {}
function greet.hello(name)
return "Hello, " .. name
end
function greet.goodbye(name)
return "Goodbye, " .. name
end
return greet
Pattern 2: Local Functions with Public Table
-- utils.lua
local function private_helper(x)
return x * 2
end
local utils = {}
function utils.process(data)
return private_helper(data)
end
return utils
Pattern 3: Return Function (for callable modules)
-- create_counter.lua
return function(initial)
local count = initial or 0
return {
increment = function() count = count + 1 return count end,
reset = function() count = 0 end,
value = function() return count end
}
end
Module Namespacing
-- db/connection.lua
local connection = {}
connection.timeout = 5000
function connection.connect(host, port)
return {host = host, port = port}
end
return connection
-- Requiring namespaced modules
local conn = require("db.connection")
-- Lua looks for: db/connection.lua or db/connection/init.lua
Common Mistakes
1. Forgetting return in module
Without return, require returns nil. Always return the module table.
2. Using global variables in modules
Use local for all module internals. Global variables pollute the namespace and cause collisions.
3. Circular dependencies
Module A requires B, B requires A. This causes one module to be nil when the other tries to use it.
4. Modifying package.path at runtime
Changing package.path after modules are loaded won't affect already-required modules.
5. Expecting hot-reload
require caches modules. To reload, set package.loaded.my_module = nil and require again.
Practice Questions
1. What does require return? The return value of the loaded module file (typically a table). If the module doesn't return anything, require returns true.
2. How does Lua find modules?
It searches package.path for .lua files and package.cpath for C libraries (.so/.dll). Directories are separated by ;, ? is replaced with the module name.
3. Can you reload a module without restarting?
Yes. Set package.loaded.module_name = nil and call require("module_name") again. This is useful for development.
Challenge: Create a module structure with db/connection.lua, db/query.lua, and a main script that uses both.
FAQ
{{< faq question="What is the difference between require and dofile?" >}} require caches the module (loads once) and searches package.path. dofile loads the file every time and uses the given path literally. {{< /faq >}}
{{< faq question="Can require load C libraries?" >}}
Yes. C libraries with a proper luaopen_* function can be loaded with require. The library must be in package.cpath.
{{< /faq >}}
{{< faq question="How do I handle circular dependencies?" >}} Restructure code to avoid circular deps. Extract shared code into a third module, or use Lazy Loading (require inside functions instead of at the top level). {{< /faq >}}
{{< faq question="What is package.preload?" >}}
A table where you can pre-register module loaders. package.preload["mymod"] = function() ... end lets require load modules without file access.
{{< /faq >}}
{{< faq question="Can I use relative paths with require?" >}} No. require uses absolute names relative to package.path. Use LuaRocks or manipulate package.path for project-relative imports. {{< /faq >}}
What's Next
Now that you understand modules, learn how to embed Lua in C applications.
| Topic | Description | Link |
|---|---|---|
| C API | Embedding and extending Lua | {{< ref "11-c-api" >}} |
| Love2D | Game Development with Lua | {{< ref "12-love2d" >}} |
| Python | Compare with Python modules | Python |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro