package.path and package.cpath
Configure search paths for Lua and C modules.
package.path and package.cpath is a free Lua Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
package.path Contents
package.path is a string of search patterns separated by semicolons. Each pattern has a ? placeholder that gets replaced by the module name (with dots converted to directory separators). Lua tries each pattern in order until a file is found.
print(package.path)
-- ./?.lua;./?.luac;/usr/local/share/lua/5.4/?.lua;...
-- Dots in module names become directory separators
-- require("foo.bar") -> searches for foo/bar.lua
print(("foo.bar"):gsub("%.", "/")) -- foo/barAdding Search Paths
Prepend paths to package.path to add search directories. Appending adds lower-priority locations. Set this before any require calls that need the new paths.
-- Add multiple directories
package.path = table.concat({
"./?.lua",
"./lib/?.lua",
"./lib/?/init.lua",
package.path, -- keep existing paths
}, ";")
-- Now require("json") searches:
-- ./json.lua -> ./lib/json.lua -> ./lib/json/init.lua -> ...package.cpath for C Extensions
package.cpath is the search path for C extension modules (shared libraries: .so on Linux, .dll on Windows, .dylib on macOS). The naming convention matches system shared library conventions.
print(package.cpath)
-- ./?.so;/usr/local/lib/lua/5.4/?.so;...
-- Add a local C library directory
package.cpath = "./clib/?.so;" .. package.cpath
-- require("myextension") will now search:
-- ./clib/myextension.soLUA_PATH Environment Variable
The LUA_PATH environment variable sets the initial value of package.path. A ;; in LUA_PATH is replaced by the default path. Use this to configure search paths without modifying scripts — useful for deployment.
-- Set before launching Lua:
-- export LUA_PATH="./?.lua;./lib/?.lua;;"
-- The ";;" expands to the built-in default path
-- In Lua, check what was set:
print(package.path)
-- You can also use LUA_CPATH for C paths:
-- export LUA_CPATH="./clib/?.so;;"package.searchpath
package.searchpath(name, path) searches for a file matching the name in the path string. It returns the first match found, or nil and an error message listing all locations tried. Useful for finding files without actually loading them.
local file, err = package.searchpath("json", package.path)
if file then
print("Found:", file)
else
print("Not found. Tried:\n" .. err)
end
-- Useful for checking if a module exists:
local function moduleExists(name)
return package.searchpath(name, package.path) ~= nil
end
print(moduleExists("json"))require Search Algorithm
When you call require("mod"), Lua follows this order: (1) check package.loaded, (2) check package.preload, (3) search package.path for a .lua file, (4) search package.cpath for a C library. The first match wins.
-- Simulate what require does:
local function myRequire(name)
-- 1. Check cache
if package.loaded[name] ~= nil then
return package.loaded[name]
end
-- 2. Check preload
if package.preload[name] then
return package.preload[name]()
end
-- 3. Search path
local file = package.searchpath(name, package.path)
if file then
return dofile(file) -- simplified
end
error("module not found: " .. name)
endLoader Functions
package.searchers (formerly package.loaders) is an array of functions that try to find and load a module. You can add custom searchers to this table. Each searcher receives a module name and returns a loader function or nil.
-- Add a custom searcher that loads from a table
local builtins = {
myconfig = function()
return {host="localhost", port=8080}
end
}
table.insert(package.searchers, 1, function(name)
local loader = builtins[name]
if loader then return loader end
end)
local cfg = require("myconfig")
print(cfg.host, cfg.port) -- localhost 8080Module Name Conventions
Module names are hierarchical using dots: "mylib.utils". The conventional top-level namespace is your project or organization name to avoid conflicts. Lowercase is standard. Avoid dashes in module names (use underscores instead) as they conflict with Lua syntax.
-- Good: hierarchical, lowercase
-- require("myapp.db.connection")
-- require("myapp.utils.string")
-- Bad: dashes cause syntax issues in dot notation
-- local my-module = require("my-module") -- SYNTAX ERROR
local mymodule = require("my_module") -- okPath Debugging
When require fails to find a module, the error message lists all paths tried. Print package.path to see the search order. Use package.searchpath to check specific module paths interactively.
-- Debug require failures:
local ok, err = pcall(require, "missing_module")
if not ok then
-- The error message shows all tried paths
print("require failed:")
print(err)
print("\nCurrent package.path:")
for path in package.path:gmatch("[^;]+") do
print(" " .. path)
end
endResetting to Default Path
If you want a clean, minimal path without system defaults, you can reset package.path entirely. This is useful for embedded Lua environments where the file system is limited or sandboxed.
-- Minimal path for embedded environment
package.path = "./?.lua;./lib/?.lua"
package.cpath = "./?.so"
-- Or get just the current directory patterns:
local function justLocal()
return "./?.lua;./?/init.lua"
end
print("Minimal path:", justLocal())Quick Check
What does the ? in a package.path pattern represent?
Recap: package.path
Summary:
package.path: Lua file search patterns;?= module namepackage.cpath: C library search patterns- Prepend to add high-priority directories
LUA_PATH/LUA_CPATHenv vars set initial pathspackage.searchpath: check if a module is findable- Add custom searchers via
package.searchers
Frequently asked questions
Is the “package.path and package.cpath” lesson free?
Yes — the full text of “package.path and package.cpath” is free to read here on the web, and the Lua Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Lua Academy course, upgrade to CoddyKit PRO.
What will I learn in “package.path and package.cpath”?
Configure search paths for Lua and C modules. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Lua Academy?
No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “package.path and package.cpath” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Lua Academy lesson?
Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The require Function
- Writing a Module File
- package.path and package.cpath
- Module Patterns and Best Practices