Emergency server help: get in touch

Lua Cheat Sheet: Lua 5.4 Syntax, Tables and Patterns

A compact Lua 5.4 reference with tables for operators, string patterns, tables, functions, error handling, metatables and file access.

Published 7 min read

Short answer: Lua 5.4 is a small language built around one data structure, the table, which serves as array, dictionary and object. Use local for every variable, .. to join strings, #t for length, ipairs and pairs to loop, pcall to catch errors, and metatables with __index for classes. Arrays start at 1, only nil and false are false, and 5.4 adds integers, //, <const> and <close> variables.

The examples in this Lua cheat sheet were run with Lua 5.4.6 on 9 October 2026. Lua 5.5 has since been released; this sheet targets 5.4.

Values, types and operators

SyntaxWhat it doesExample
local x = 1Local variable. Without local it is globallocal port = 8080
nil, boolean, number, string, table, functionMain types; type(x) returns the nametype({}) gives "table"
math.type(x)"integer" or "float" (nil for non-numbers)math.type(1.0) gives "float"
/ and //Float division / floor division7 / 2 is 3.5, 7 // 2 is 3, -7 // 2 is -4
%, ^Modulo; power (always a float)2 ^ 10 gives 1024.0
&, |, ~, <<, >>, ~xBitwise on integers3 ~ 5 (XOR) gives 6
==, ~=Equal / not equal. No type coercion"10" == 10 is false
and, or, notReturn an operand, not a boollocal v = x or "default"
tonumber(s, base), tostring(v)Conversionstonumber("0x10") is 16; tonumber("abc") is nil
math.tointeger(3.0)Float to integer if exactReturns fail (nil) otherwise

Only nil and false are false: 0 and "" are true. Integers are 64-bit and wrap around: math.maxinteger + 1 == math.mininteger is true.

Strings and patterns

FunctionWhat it doesExample
..Concatenation"Host " .. name .. ":" .. port
#s vs utf8.len(s)Bytes vs UTF-8 characters#"héllo" is 6, utf8.len gives 5
s:upper(), s:sub(i, j)Method syntax on strings; negative indexes count from the end("abcdef"):sub(-3) gives "def"
string.format()printf-stylestring.format("%-8s %5d", h, p)
s:find(text, 1, true)Plain find (4th argument disables patterns)ip:find(".", 1, true)
s:match(pat)First match; returns capturesline:match("^(%w+)%s*=%s*(%w+)$")
s:gmatch(pat)Iterate over matchesfor w in s:gmatch("%a+") do … end
s:gsub(pat, repl)Replace all; also returns the count("a,b"):gsub(",", ";")
string.rep(s, n, sep)Repeatstring.rep("ab", 3, ",")
[[ … ]]Long string, no escapesMulti-line text

Lua patterns are not regular expressions. There is no | alternation and no {n} counts, and the escape character is %, not backslash.

Pattern itemMatches
%d, %a, %w, %sDigit, letter, alphanumeric, whitespace (upper case negates: %S)
. and %.Any character / a literal dot
*, +, -, ?0 or more (greedy), 1 or more, 0 or more (lazy), optional
[^/]+Character class and negation
^, $, ( )Anchors and captures
(" x "):match("^%s*(.-)%s*$")The usual trim idiom

Tables: arrays and dictionaries

SyntaxWhat it doesExample
{10, 20, 30}Array part, indexes start at 1list[1] is 10
{host = "db01", ["max-conn"] = 100}Dictionary; brackets for keys that are not namescfg.host, cfg["max-conn"]
#tLength of a sequence (no nil holes)list[#list + 1] = 40 appends
table.insert(t, v) / table.insert(t, 1, v)Append / insert at a positiontable.insert(list, 1, 5)
table.remove(t)Remove and return the last (or given) elementtable.remove(list, 1)
table.concat(t, sep)Join strings and numberstable.concat(list, ",")
table.sort(t, cmp)Sort in placetable.sort(t, function(a, b) return a > b end)
table.unpack(t) / table.pack(...)Spread / collect values (.n counts nils)table.pack(1, nil, 3).n is 3
t.key = nilDelete a keycfg.port = nil
next(t) == nilIs the table empty?Works for any table
for i, v in ipairs(list) do print(i, v) end   -- 1..n in order, stops at the first nil
for k, v in pairs(cfg) do print(k, v) end     -- every key, order not defined

Control flow

SyntaxExample
if … then … elseif … else … endif code >= 500 then … elseif code >= 400 then … end
Numeric forfor i = 10, 1, -3 do … end (start, stop, step)
Generic forfor line in io.lines(path) do … end
while / repeat … untilrepeat i = i - 1 until i <= 0
breakLeaves the innermost loop
goto continue … ::continue::Lua has no continue; this is the usual substitute
a and b or cTernary idiom; wrong if b can be nil or false

Functions, varargs and closures

SyntaxWhat it doesExample
local function f(a, b) … endLocal function (can call itself recursively)local function greet(n) … end
greeting = greeting or "Hello"Default arguments idiomMissing arguments are nil
return a, bMultiple return valueslocal ok, err = f()
... and select("#", ...)Varargs; count including nilslocal args = {...}
select(n, ...)Values from position nselect(2, "a", "b", "c") gives b, c
ClosuresInner functions keep their upvaluessee below
obj:method(x)Same as obj.method(obj, x)srv:dsn()
local function counter()
  local c = 0
  return function() c = c + 1; return c end
end
local nextc = counter()
nextc()
print(nextc())   --> 2

Errors: pcall, error and assert

CallWhat it doesExample
error(msg, level)Raise; level 0 omits the file:line prefixerror("bad port", 0)
pcall(f, ...)Protected call: returns true, results or false, errlocal ok, err = pcall(load_cfg)
xpcall(f, handler)As pcall, with a message handlerxpcall(f, debug.traceback)
assert(v, msg)Raise if v is false or nil; returns all its argumentslocal fh = assert(io.open(path))
return nil, "msg"Library convention for soft failureio.open returns nil and the reason
error({code = 42})Any value can be an error objectCheck with type(err) == "table"

Metatables and objects

local Server = {}
Server.__index = Server

function Server.new(host, port)
  local self = setmetatable({}, Server)
  self.host, self.port = host, port or 22
  return self
end

function Server:dsn() return self.host .. ":" .. self.port end
Server.__tostring = function(s) return "Server(" .. s:dsn() .. ")" end

local srv = Server.new("db01", 3306)
print(srv:dsn(), tostring(srv))   --> db01:3306   Server(db01:3306)
MetamethodCalled when
__indexA missing key is read (table or function); basis of classes and defaults
__newindexA missing key is assigned; use for read-only tables
__tostringtostring(obj) or print(obj)
__eq, __lt, __leComparisons
__add, __concat, __lenArithmetic, .. and #
__callThe table is called like a function
__closeA <close> variable goes out of scope (5.4)
__gcThe object is garbage-collected

For inheritance, give the subclass table a metatable whose __index is the parent: local Web = setmetatable({}, {__index = Server}), then Web.__index = Web.

New in Lua 5.4 and coroutines

FeatureExampleNote
Constant variablelocal limit <const> = 10Assigning again is a compile error
To-be-closed variablelocal fh <close> = assert(io.open(p))fh is closed when the block ends, even on error
Integer subtype (5.3+)math.type(3) is "integer"64-bit integers alongside floats
Warningswarn("@on"), lua -WOff by default
Coroutine generatorcoroutine.wrap(function() coroutine.yield(1) end)Call the result to resume
Coroutine controlcoroutine.resume(co, x), coroutine.status(co)Status is suspended, running or dead

Files, os and running commands

TaskCode
Read a whole filelocal fh = assert(io.open(p, "r")); local s = fh:read("a"); fh:close()
Loop over linesfor line in io.lines(p) do … end
Write or appendio.open(p, "w") / io.open(p, "a"), then fh:write(s)
Command outputlocal p = io.popen("uptime"); local out = p:read("a"); p:close()
Run a commandlocal ok, how, code = os.execute("true")
Environment and timeos.getenv("HOME"), os.time(), os.date("!%Y-%m-%d %H:%M:%S")
Delete or renameos.remove(p), os.rename(a, b)
Load a modulelocal json = require("cjson") (searches package.path and package.cpath)

For server admins: Lua is embedded in tools you may already run, but not always as 5.4. Redis scripts (EVAL) use Lua 5.1, and OpenResty uses LuaJIT, which is 5.1-compatible, so //, bitwise operators, goto (in Redis) and <close> are not available there. A quick status-code count over an access log in plain Lua 5.4:

local counts = {}
for line in io.lines("access.log") do
  local status = line:match('" (%d%d%d) ')
  if status then counts[status] = (counts[status] or 0) + 1 end
end
for code, n in pairs(counts) do print(code, n) end

Official documentation (checked 9 October 2026): Lua 5.4 Reference Manual · Lua 5.4 manual contents and index · Lua 5.4 readme: changes since 5.3 · Lua versions

Lua Cheat Sheet at a glance

Lua Cheat Sheet – short answer
In short: A compact Lua 5.4 reference with tables for operators, string patterns, tables, functions, error handling, metatables and file access.
Lua Cheat Sheet – what this guide covers
Lua Cheat Sheet: what this guide covers.

Related guides: Luau Cheat Sheet: Type Annotations, Syntax and Roblox Basics · Python Cheat Sheet: Syntax, Data Types and File Handling · C Cheat Sheet: C17 and C23 Syntax, Memory and gcc Flags.

Reading a lot of our guides? Go ad-free with srvScripts Pro for $6 a month. It also pays for new guides. Cancel any time.

Share this guide

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.