Anatomy of a Lua file
Lua is a powerful, efficient, lightweight, embeddable scripting language common in game development and embedded systems.
File extensions: .lua
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside a Lua file
Comment
Single-line (--) or block (--[[...]]), ignored by the interpreter.
-- starts a comment that runs to the end of the line, the most common form in everyday Lua code. A --[[ / ]] pair brackets a block comment that can span many lines, which is handy for a file-level overview or for temporarily disabling a chunk of code. Both forms are stripped before execution and have no effect on the running program. Because the block form uses the same long-bracket syntax as multi-line strings, some editors and linters get confused if a ]] appears inside the commented-out text, so nested block comments are best avoided.
Variable declaration (global)
Variables not declared with local are global by default.
Simply writing appName = "My Lua App" at any scope creates or assigns a global variable, stored in a shared global table (_G in standard Lua). This is the opposite default from most languages, where a bare assignment is local unless declared otherwise. Globals are visible everywhere, including inside functions and other files running in the same interpreter state, which makes them convenient but easy to collide or leak by accident. Idiomatic Lua reserves globals for a small, deliberate set of names and pushes everything else into local variables or tables.
Variable declaration (local)
local limits a variable's scope to the current block.
The local keyword declares a variable that only exists from that point to the end of the enclosing block (a function, loop, do...end, or the file itself). local version = 1.2 shadows any global of the same name and is cleaned up automatically once the block ends. Lua encourages local over globals for two reasons: it avoids accidental name collisions, and local variable access compiles to a fast register lookup rather than a table lookup, which matters in a language often embedded in performance-sensitive hosts like games.
Table (data structure)
An associative array used for maps, lists, and objects ({}).
The table is Lua's only built-in data structure, and it does the job of arrays, dictionaries, records, and objects all at once. { debug = true, max_users = 100 } creates a table with string keys, but the same braces also build a list: {"/usr/bin", "/usr/local/bin"} implicitly keys its entries 1, 2, 3, ... Unlike most languages, Lua sequences are 1-indexed, not 0-indexed. Because tables can mix named fields and numeric entries, and can even hold functions or other tables as values, they double as the mechanism Lua uses for modules, namespaces, and prototype-based objects (with help from metatab
Field (table element)
A key-value pair within a table.
debug = true and max_users = 100 are fields: each associates a key (here, a string used as an identifier) with a value inside the enclosing table literal. Fields can be read or written afterward with dot syntax (config.debug) when the key is a valid identifier, or bracket syntax (config["debug"]) for arbitrary keys. A field can hold any Lua value, including another table, which is how paths = {"/usr/bin", "/usr/local/bin"} nests a list inside config, accessed later as config.paths. Assigning nil to a field removes it from the table entirely.
Function definition
A reusable block of code (function ... end).
local function greetUser(name) ... end binds a function value to a name, scoped like any other local. Functions are first-class values in Lua: they can be stored in variables or table fields, passed as arguments, and returned from other functions, which is what makes callbacks and event handlers so natural in the language. A function with no explicit return yields nil when called. Lua also supports variadic parameters (...) and multiple return values (return a, b), both of which are used throughout the standard library.
String concatenation
Joins strings using the .. operator.
"Hello, " .. name .. "!" builds a new string by concatenating each operand with the .. operator. Lua has no + overload for strings and no built-in interpolation syntax, so concatenation (or string.format) is the standard way to build a message out of pieces. Numbers are coerced to their string form automatically when used with .., so "v" .. version works without an explicit conversion. Chaining many .. calls to build a large string in a loop is relatively slow, since each one allocates a new string; table.concat is the idiomatic alternative for joining many pieces at once.
Control flow (loop)
Executes code repeatedly (for, while, repeat).
for i, path in ipairs(config.paths) do ... end is a generic for loop: ipairs returns an iterator that walks a table's array part in order, yielding an index and value each pass. Lua also has a numeric for i = 1, 10 do ... end form, a while that tests before each pass, and a repeat ... until that tests after, guaranteeing at least one iteration. pairs(t) is the counterpart to ipairs for visiting every key in a table, including non-numeric ones, though the order is unspecified. break exits a loop early; Lua has no continue keyword, so the usual workaround is wrapping the remaining body in an if.
Control flow (conditional)
Executes code based on a condition (if, elseif, else).
if config.debug then ... else ... end branches on truthiness. Lua's notion of falsy is narrow: only false and nil are falsy, so 0 and "" (unlike in many other languages) both count as true. Every if must be closed with a matching end. elseif chains additional conditions without nesting a nested if inside each else. Because if is a statement rather than an expression, Lua code that needs a conditional expression typically reaches for condition and a or b, which works as a ternary as long as a is never false or nil.
Function call
Executing a function, such as print(...) or a user-defined one.
print(message) and greetUser("Alice") both call a function by following its name with parentheses containing the arguments. print is part of the small set of global functions the standard library installs, writing its arguments to standard output separated by tabs: the everyday debugging tool in Lua, much like console.log elsewhere. A call can be used as a statement on its own (greetUser("Alice")) or as an expression whose result feeds something else, and since functions can return multiple values, a call like return true at the end of a function simply hands that value back to whoever called
Official Lua site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.