100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Modules and require

Learn how Lua organizes reusable code into modules with the require function, package.path, and the standard return-a-table pattern.

OOP & ModulesBeginner8 min readJul 10, 2026
Analogies

The require Function

require("modname") is Lua's standard mechanism for loading external code. It searches package.path (a semicolon-separated list of file path templates using ? as a placeholder for the module name) for a matching .lua file, runs that file exactly once, caches its return value in package.loaded[modname], and returns that value on every subsequent require call for the same name. This caching means a module's top-level code executes only once per program run, no matter how many files require it.

🏏

Cricket analogy: A commentary panel only needs to fetch a player's official bio from the ICC database once per broadcast, then reuses the cached data for every mention afterward, mirroring how require() caches a module after the first load.

lua
-- File: mathutils.lua
local M = {}

function M.square(x)
  return x * x
end

function M.clamp(x, lo, hi)
  if x < lo then return lo end
  if x > hi then return hi end
  return x
end

return M

-- File: main.lua
local mathutils = require("mathutils")
print(mathutils.square(5))       --> 25
print(mathutils.clamp(15, 0, 10)) --> 10

The Return-a-Table Convention

The idiomatic Lua module pattern is to declare a local table (commonly named M or the module name itself) at the top of the file, attach every public function and constant to it as the file progresses, and finish with return M. Anything declared local and not attached to that table stays private to the module, effectively giving you file-level encapsulation, since require only exposes whatever value the file explicitly returns.

🏏

Cricket analogy: A franchise only reveals its final playing XI on the team sheet handed to the umpire, keeping net-session experiments private, the way a module only exposes what's attached to the returned table.

package.path and Search Locations

package.path holds the templates Lua uses to locate .lua files, such as ./?.lua;./?/init.lua;/usr/local/share/lua/5.4/?.lua, where each ? is replaced with the dotted module name (dots become path separators). package.cpath serves the same purpose for compiled C libraries (.so/.dll). You can prepend project-specific directories by modifying package.path at the top of your entry script, which is the common way to make require("mymodule") find files inside a custom lib/ folder.

🏏

Cricket analogy: A scout checks a shortlist of specific regional academies in a fixed order when looking for a promising player, similar to how require() checks each template in package.path in sequence.

require uses dots in the module name as a hint for nested paths only by convention in some path templates (e.g. require("mypkg.util") looking for mypkg/util.lua), but it does NOT automatically convert dots to slashes unless your package.path templates are written to do so — always verify your path templates match your actual directory layout.

  • require("name") loads a .lua file found via package.path, executes it once, and caches the result in package.loaded.
  • Subsequent require calls for the same module name return the cached value instantly without re-running the file.
  • The idiomatic module pattern builds a local table, attaches public functions to it, and ends with return M.
  • Locals not attached to the returned table are private to the module file, providing simple encapsulation.
  • package.path is a semicolon-separated list of ?-templated search paths; package.cpath does the same for C libraries.
  • You can prepend custom directories to package.path at program startup to support project-specific lib/ folders.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#LuaStudyNotes#ModulesAndRequire#Modules#Require#Function#Return#StudyNotes#SkillVeris#ExamPrep