require() (Module Loading)
In Lua, require() loads modules and allows code to be split across multiple files. The common pattern is to create a module as a file that returns a table, which organizes functionality while preventing namespace pollution.
Syntax
-- -----------------------------------------------
-- Basic module file syntax (module_name.lua)
-- -----------------------------------------------
-- Create a table for the module and return it
local M = {} -- define the module table
-- Define a function in the module
function M.greet(name)
return "Hello, " .. name
end
-- Return the table to expose it as a module
return M
-- -----------------------------------------------
-- Loading side (main.lua)
-- -----------------------------------------------
-- Load the module with require()
local mymod = require("module_name") -- the .lua extension is not needed
print(mymod.greet("Lua")) -- Hello, Lua
-- -----------------------------------------------
-- Checking and setting the package path
-- -----------------------------------------------
-- Check the path Lua uses to search for modules
print(package.path)
-- Add the current directory to the search path (semicolon-separated)
package.path = package.path .. ";./lib/?.lua"
-- -----------------------------------------------
-- Module cache (package.loaded)
-- -----------------------------------------------
-- Modules are cached once require() is called
local mod1 = require("module_name") -- reads the file
local mod2 = require("module_name") -- returned from cache
print(mod1 == mod2) -- true (same table)
Syntax Reference
| Syntax / Concept | Description |
|---|---|
require("name") | Loads a module. Omit the .lua extension and use dots as path separators (e.g., require("lib.util")). |
| Module return value | A module file returns a table or value with return at the end. This return value becomes the return value of require(). |
local M = {} pattern | Creating a local table, storing functions in it, and returning it with return M is the most common module creation pattern. |
package.path | A string listing the paths Lua searches for modules. ? is expanded with the module name. Multiple paths are separated by semicolons. |
package.loaded | A cache table of loaded modules. A file is executed only once no matter how many times require() is called for the same module. |
package.preload | A table for pre-registering modules without files. Used for defining built-in modules. |
| Submodule (dot notation) | A module in a subdirectory can be specified with dots, like require("lib.util"). Dots are converted to path separators. |
| Module reload | Delete the cache with package.loaded["name"] = nil and then call require() again to reload a module. |
Sample Code
kof_fighter.lua (module file)
-- kof_fighter.lua — Module that manages KOF fighter data
-- Defined as a module to be loaded via require()
local M = {} -- module table
-- -----------------------------------------------
-- Private data used only inside the module
-- (local prevents direct access from outside)
-- -----------------------------------------------
local fighters = {
{ name = "Kyo Kusanagi", team = "Japan Team", power = 95, style = "Kusanagi-style variant" },
{ name = "Iori Yagami", team = "Yagami Team", power = 97, style = "Yagami-style" },
{ name = "Terry Bogard", team = "Fatal Fury Team",power = 93, style = "Goou Wave" },
{ name = "Mai Shiranui", team = "Women's Team II",power = 88, style = "Shiranui Ninjutsu" },
{ name = "Leona Heidern", team = "Heidern Unit", power = 90, style = "Orochi Blood" },
}
-- -----------------------------------------------
-- Returns a list of all fighters (read-only copy)
-- -----------------------------------------------
function M.get_all()
local result = {}
for i, f in ipairs(fighters) do
result[i] = {
name = f.name,
team = f.team,
power = f.power,
style = f.style,
}
end
return result
end
-- -----------------------------------------------
-- Searches for a fighter by name
-- Returns nil if not found
-- -----------------------------------------------
function M.find_by_name(name)
for _, f in ipairs(fighters) do
if f.name == name then
return {
name = f.name,
team = f.team,
power = f.power,
style = f.style,
}
end
end
return nil -- not found
end
-- -----------------------------------------------
-- Returns a ranking sorted by power
-- -----------------------------------------------
function M.get_ranking()
local sorted = M.get_all() -- get a copy and sort it
table.sort(sorted, function(a, b)
return a.power > b.power -- descending order
end)
return sorted
end
-- -----------------------------------------------
-- Module version info
-- -----------------------------------------------
M.version = "1.0.0"
return M -- return the table to expose it as a module
kof_stats.lua (submodule file)
-- kof_stats.lua — Submodule for fighter statistics
-- Depends on the kof_fighter module
local fighter = require("kof_fighter") -- load another module
local M = {}
-- -----------------------------------------------
-- Calculates the average power of all fighters
-- -----------------------------------------------
function M.average_power()
local all = fighter.get_all()
if #all == 0 then return 0 end
local total = 0
for _, f in ipairs(all) do
total = total + f.power
end
return total / #all
end
-- -----------------------------------------------
-- Filters fighters with power at or above a threshold
-- -----------------------------------------------
function M.filter_by_power(threshold)
local all = fighter.get_all()
local result = {}
for _, f in ipairs(all) do
if f.power >= threshold then
result[#result + 1] = f -- add fighters that meet the condition
end
end
return result
end
return M
kof_main.lua (main file)
-- kof_main.lua — Main file that loads modules via require()
-- -----------------------------------------------
-- Loading modules
-- -----------------------------------------------
local fighter = require("kof_fighter") -- fighter data module
local stats = require("kof_stats") -- statistics module (depends on kof_fighter)
-- -----------------------------------------------
-- Verify the cache using package.loaded
-- -----------------------------------------------
-- Calling require() twice returns the same table
local fighter2 = require("kof_fighter")
print("=== Cache check ===")
print("fighter == fighter2: " .. tostring(fighter == fighter2)) -- true
print("Version: " .. fighter.version)
print("")
-- -----------------------------------------------
-- Display all fighters
-- -----------------------------------------------
print("=== KOF Fighter List ===")
local all = fighter.get_all()
for _, f in ipairs(all) do
print(string.format(" %-22s [%s] Power: %d", f.name, f.team, f.power))
end
print("")
-- -----------------------------------------------
-- Name search
-- -----------------------------------------------
print("=== Name search: Kyo Kusanagi ===")
local kyo = fighter.find_by_name("Kyo Kusanagi")
if kyo then
print(string.format(" Name: %s", kyo.name))
print(string.format(" Team: %s", kyo.team))
print(string.format(" Style: %s", kyo.style))
else
print(" Not found")
end
print("")
-- -----------------------------------------------
-- Ranking display
-- -----------------------------------------------
print("=== Power Ranking ===")
local ranking = fighter.get_ranking()
for i, f in ipairs(ranking) do
print(string.format(" #%d: %-22s Power: %d", i, f.name, f.power))
end
print("")
-- -----------------------------------------------
-- Using the stats module
-- -----------------------------------------------
print("=== Statistics ===")
print(string.format(" Average power: %.1f", stats.average_power()))
print("")
print("=== Fighters with power >= 90 ===")
local strong = stats.filter_by_power(90)
for _, f in ipairs(strong) do
print(string.format(" %s (Power: %d)", f.name, f.power))
end
print("")
-- -----------------------------------------------
-- Module reload (clear cache and re-require)
-- -----------------------------------------------
print("=== Module reload ===")
package.loaded["kof_fighter"] = nil -- clear the cache
local fighter_reloaded = require("kof_fighter") -- re-execute the file
print("Version after reload: " .. fighter_reloaded.version)
lua kof_main.lua === Cache check === fighter == fighter2: true Version: 1.0.0 === KOF Fighter List === Kyo Kusanagi [Japan Team] Power: 95 Iori Yagami [Yagami Team] Power: 97 Terry Bogard [Fatal Fury Team] Power: 93 Mai Shiranui [Women's Team II] Power: 88 Leona Heidern [Heidern Unit] Power: 90 === Name search: Kyo Kusanagi === Name: Kyo Kusanagi Team: Japan Team Style: Kusanagi-style variant === Power Ranking === #1: Iori Yagami Power: 97 #2: Kyo Kusanagi Power: 95 #3: Terry Bogard Power: 93 #4: Leona Heidern Power: 90 #5: Mai Shiranui Power: 88 === Statistics === Average power: 92.6 === Fighters with power >= 90 === Kyo Kusanagi (Power: 95) Iori Yagami (Power: 97) Terry Bogard (Power: 93) Leona Heidern (Power: 90) === Module reload === Version after reload: 1.0.0
Common Mistakes
Modules loaded with require are returned from cache on subsequent calls
Once a module is loaded with require(), it is cached in package.loaded. Even if the file is updated, calling require() again does not reflect the changes. To reload a module, delete the cache entry with package.loaded["name"] = nil and call require() again.
-- NG (file changes are not picked up after the first load)
local fighter = require("kof_fighter")
-- after updating kof_fighter.lua ...
local fighter2 = require("kof_fighter") -- cache is returned (changes not reflected)
-- OK (clear the cache and require again)
package.loaded["kof_fighter"] = nil
local fighter2 = require("kof_fighter") -- re-executes the file
Missing return at the end of a module file makes require return true
In Lua, a module returns its value by using return at the end of the file. If return is forgotten, require() returns true, and attempting to call a function on it causes an error.
-- NG (module without return: return_missing.lua)
local M = {}
function M.greet(name)
return "Hello, " .. name
end
-- forgot: return M
-- OK (always return the table at the end of the module)
local M = {}
function M.greet(name)
return "Hello, " .. name
end
return M
Dots in require("foo.bar") are interpreted as directory separators
Dots in the string passed to require() are converted to path separators (/ or \) when expanding package.path patterns. require("kof.fighter") searches for kof/fighter.lua. If you want a dot as part of a file name, restructure the file into a subdirectory.
-- NG (kof.fighter is interpreted as a subdirectory, not a file name with a dot)
-- file: kof.fighter.lua
local fighter = require("kof.fighter") -- searches for kof/fighter.lua
-- OK (place the file in a directory structure that matches the dot notation)
-- file: kof/fighter.lua
local fighter = require("kof.fighter") -- loads kof/fighter.lua (correct)
Overview
Lua's require() is the standard function for loading modules. Pass the module name as a string (omit the .lua extension). Submodule paths can be specified with dot notation (e.g., require("lib.util")), where dots are converted to path separators.
The search path is managed by package.path, where ? is expanded with the module name. By default, the current directory and Lua's standard library paths are included. Additional paths can be added with package.path = package.path .. ";./lib/?.lua".
Loaded modules are cached in package.loaded, so the same module file is executed only once regardless of how many times require() is called. To reload a module, delete the cache with package.loaded["name"] = nil and call require() again. The best practice for creating modules is to define a local table with local M = {}, store functions in it, and return it with return M. By keeping the internal implementation local and only exposing what is needed in the table, namespace pollution is prevented. For table fundamentals, also refer to Table Basics.
If you find any errors or copyright issues, please contact us.