Skip to content

Lua Modules Guide — require, Module Patterns, and Package Organization

DodaTech Updated 2026-06-28 4 min read

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

-- 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