loadfile
loadfile ([filename [, mode [, env]]]) Overview
loadfile reads a Lua chunk from a file on disk, compiles it, and hands it back as a function. It does not run the chunk; that is your job, with a call to the returned value. The Lua 5.4 manual puts it this way: “Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.”
That separation between compiling and executing is the whole reason loadfile exists. It lets you inspect a file’s syntax, swap out its environment, defer execution, or wrap the call in pcall before running it. If you do not need any of that, dofile does the same job in one step and is shorter to type.
Signature
loadfile ([filename [, mode [, env]]])
All three arguments are optional. With no arguments at all, loadfile reads a chunk from standard input.
Parameters
filename
A string path to the file to load, or nil. When omitted or nil, the chunk is read from stdin until end-of-file. The path is also used as the chunk’s name in error messages and stack traces. There is no separate chunkname parameter, unlike load.
local chunk, err = loadfile("modules/payments.lua")
mode
A string that controls which chunk formats are accepted:
| Value | Behavior |
|---|---|
"t" | Text only. Reject precompiled binary chunks. |
"b" | Binary only. Reject text chunks. |
"bt" | Both. Default. |
The default "bt" is fine for trusted code, but it is worth being explicit when loading anything you did not write yourself. Binary chunks produced by string.dump or luac are not verified beyond the outer wrapper. The Lua manual warns that “running maliciously crafted bytecode can crash the interpreter.” For untrusted input, pass mode = "t".
env
A table that becomes the chunk’s _ENV upvalue. The chunk’s globals resolve through this table, which is how you sandbox a script: pass a stripped-down environment with only the functions it is allowed to call.
local chunk = assert(loadfile("plugin.lua", "t", safe_env))
If env is omitted, the chunk uses the calling Lua state’s global environment.
Return Values
loadfile returns one of two shapes, matching load:
- On success, the compiled chunk as a function.
- On any failure (file not found, read error, syntax error, malformed binary):
nilplus an error message string.
It does not raise. That is deliberate: you can check the error and decide what to do, instead of having it propagate up. If you want it to raise, wrap the call in assert:
local chunk = assert(loadfile("greet.lua")) -- raises with the error string on failure
Examples
Load a file and call the chunk
The two files below show the standard split. greet.lua defines a function and returns it; main.lua loads the file, runs the chunk, and uses whatever the chunk returns.
greet.lua:
-- greet.lua
local function greet(name)
return "hello, " .. name
end
return greet
main.lua is the consumer. It calls loadfile, checks the return value, then runs the chunk to get the function back, and finally calls it with an argument.
main.lua:
-- main.lua
local chunk, err = loadfile("greet.lua")
if not chunk then
error("failed to load greet.lua: " .. tostring(err))
end
local greet = chunk() -- run the chunk; it returns a function
print(greet("world")) -- -> hello, world
The double-call pattern trips up a lot of people. chunk is the loaded file as a function; chunk() is the file executing and returning whatever the file’s top-level return produced.
Sandbox a script with a custom environment
-- sandbox.lua
local env = {
print = print,
pairs = pairs,
ipairs = ipairs,
tonumber = tonumber,
tostring = tostring,
-- intentionally omitted: os, io, require, dofile, loadfile, load
}
local chunk = assert(loadfile("untrusted.lua", "t", env))
chunk()
Any reference to os.execute, io.open, or require inside untrusted.lua resolves through _ENV and hits a nil, which raises an “attempt to call a nil value” error. This is the standard pattern for plugin systems, mod loaders, and user-supplied scripts.
Syntax-check a file without running it
-- lint.lua
local chunk, err = loadfile("script.lua")
if not chunk then
io.stderr:write("syntax error: " .. err .. "\n")
os.exit(1)
end
print("OK: script.lua parses")
Tools that validate Lua code (linters, formatters, build hooks) use this shape: load the file, look at the result, never call the function. Side effects in the file are not triggered.
loadfile vs dofile
dofile([filename]) is roughly equivalent to:
local function dofile(name)
local chunk, err = loadfile(name)
if not chunk then error(err) end
return chunk()
end
The behavioral difference: dofile propagates any error to its caller; loadfile hands it back to you. Reach for loadfile when you want to handle the failure locally, defer execution, or swap the chunk’s environment. Reach for dofile when you just want to run a file and let errors bubble.
Notes and Gotchas
- Forgetting to call the returned function is the most common bug.
local f = loadfile("foo.lua")does not runfoo.lua; you must callf(). - There is no
chunknameparameter. If you need a friendly name in error messages that differs from the path, useloaddirectly:load(io.open(path, "rb"):read("*a"), "@" .. friendly_name). - Default
modeis"bt", which accepts precompiled chunks. For anything that came from outside your codebase, passmode = "t"to refuse binary input. loadfiledoes not cache. Calling it twice on the same file parses the file twice and returns two distinct functions. Userequireif you want a single shared instance per path.- File-not-found and syntax errors both come back as
nil, errmsg. I/O errors start with"cannot "(e.g.,cannot open foo.lua: No such file or directory); syntax errors look likefoo.lua:LINE: .... Match the prefix if you need to tell them apart. - If the code is already a string, use
load. Reaching forloadfileon a string forces a write-then-read round trip through disk, which is wasteful and adds another failure mode.
See Also
Related reference pages:
load: load a chunk from a string or function; has achunknameparameterdofile: load and execute a file in one callrequire: cached module loaderassert: typical wrapper forloadfile’snil, errmsgreturnpcall/xpcall: protected call, useful when running a loaded chunkerror: raise an error after a load failure
Guides and tutorials:
- Sandboxing Lua: the canonical
loadfile+ custom env pattern, in depth - Lua Environments and
_ENV: how_ENVworks as a chunk upvalue - Plugin Architectures: loading user-supplied scripts at runtime
- Modules and
require: when to userequireinstead ofloadfile - File I/O: reading files and turning them into chunks