Menu
Coddy logo textTech

Luau Cheat Sheet

Type-checking modes

A comment on the first line of the file decides how strictly Luau checks it.

ModeSyntax
No type checking--!nocheck
Default: check what's annotated--!nonstrict
Strict: infer and check everything--!strict
Run a fileluau main.luau
Type-check without runningluau-analyze main.luau
Turn off one lint warning--!nolint UnknownGlobal

Basic types

Primitive types and how to annotate a variable.

OperationSyntax
Numberlocal age: number = 25
Stringlocal name: string = "Ada"
Booleanlocal ok: boolean = true
Optional (may be nil)local nick: string? = nil
Any (opt out of checking)local x: any = f()
Unknown (safer any)local x: unknown = f()
Never (always throws)function fail(): never error("boom") end
Nillocal n: nil = nil
Coroutine / bufferlocal co: thread, local b: buffer
Inferred - no annotation neededlocal hp = 100 -- number

Typed tables: arrays & maps

Tables are still Lua tables - the type says what's inside.

OperationSyntax
Array of numberslocal xs: {number} = {1, 2, 3}
Array of stringslocal names: {string} = {}
Map (string keys)local ages: {[string]: number} = {}
Map (any key type)local seen: {[Player]: boolean} = {}
Nested arraylocal grid: {{number}} = {}
Array of shapeslocal items: {{id: number}} = {}
Read-only arraylocal t = table.freeze({1, 2, 3})
Iterate (generalized, Luau only)for i, v in xs do print(i, v) end
Iterate keys and valuesfor k, v in pairs(ages) do end

Functions

Annotate parameters and the return type; -> () means returns nothing.

OperationSyntax
Typed parameters + returnfunction add(a: number, b: number): number
Returns nothingfunction log(msg: string): () end
Multiple returnsfunction split(s: string): (string, string)
Optional parameterfunction greet(name: string?) end
Default valuefunction greet(name: string?) name = name or "friend" end
Variadicfunction sum(...: number): number end
Anonymous functionlocal f = function(x: number): number return x * 2 end
Function typetype Adder = (number, number) -> number
Callback parameterfunction each(f: (number) -> ()) end

Type aliases, unions & literals

Name a type once, reuse it everywhere.

OperationSyntax
Alias a primitivetype Health = number
Uniontype Id = number | string
Optional is a union with niltype Maybe = string | nil -- same as string?
Literal (singleton) typetype Dir = "up" | "down"
Intersectiontype Both = Named & Aged
Generic aliastype List<T> = {T}
Export from a moduleexport type Point = { x: number, y: number }
Type of an existing valuetype Config = typeof(config)
Keys of a table typetype K = keyof<Point>

Table shapes & methods

Describing objects, and the self that comes with colon calls.

OperationSyntax
Inline shapelocal p: { x: number, y: number } = { x = 0, y = 0 }
Named shapetype Point = { x: number, y: number }
Optional propertytype User = { name: string, age: number? }
Shape + indexertype Bag = { count: number, [string]: any }
Extend a shapetype Admin = User & { level: number }
Method (colon shorthand)function Point.move(self: Point, dx: number) end
Method in a typetype Point = { move: (self: Point, dx: number) -> () }
Constructor patternfunction Point.new(x: number): Point end
Frozen constants (enum-ish)local Color = table.freeze({ Red = 1, Blue = 2 })

Generics

One function or type that works for many value types.

OperationSyntax
Generic functionfunction id<T>(x: T): T return x end
Two type parametersfunction pair<A, B>(a: A, b: B): (A, B) end
Generic over an arrayfunction first<T>(xs: {T}): T? return xs[1] end
Generic type aliastype Stack<T> = { items: {T} }
Instantiate an aliaslocal s: Stack<string> = { items = {} }
Generic map functionfunction map<T, U>(xs: {T}, f: (T) -> U): {U} end
Generic pack (variadic)function call<T...>(f: () -> T...): T... end

Narrowing, assertions & guards

Convincing the type checker that a value is what you know it is.

OperationSyntax
Type assertion (cast)local n = value :: number
Assert through anylocal n = (value :: any) :: number
Narrow with typeofif typeof(x) == "string" then -- x is string end
Narrow an optionalif name then print(#name) end
Early return on nilif not name then return end
Narrow a literal unionif dir == "up" then end
Runtime check + type errorassert(typeof(id) == "number", "id must be a number")
Assert not nil, then uselocal item = assert(find(id), "missing item")

Operators & syntax Lua doesn't have

The everyday quality-of-life additions - this is where Luau code stops looking like Lua.

OperationSyntax
Add and assignhp += 10
Subtract / multiply / dividehp -= 5, dmg *= 2, dmg /= 2
Floor-divide and assignn //= 2
Modulo / power and assignn %= 3, n ^= 2
Concatenate and assignmsg ..= "!"
Floor divisionlocal half = 7 // 2 -- 3
String interpolationHello, {name}! You have {n} items. (wrap in backticks)
Interpolate an expressionTotal: {price * qty} (wrap in backticks)
Continue a loopfor _, v in xs do if v < 0 then continue end end
if-then-else expressionlocal label = if hp > 0 then "alive" else "dead"
Chained else-if expressionlocal t = if n > 0 then "pos" elseif n < 0 then "neg" else "zero"
Binary / separated number literals0b1010, 1_000_000

Library extras & Lua differences

Standard-library functions Luau adds, and the Lua features it removes.

ItemDetail
Find a value in an arraytable.find(xs, 42) -- index or nil
Shallow copylocal copy = table.clone(t)
Make immutable / checktable.freeze(t), table.isfrozen(t)
Preallocate an arraytable.create(10, 0)
Clamp / round / signmath.clamp(x, 0, 1), math.round(x), math.sign(x)
Bitwise opsbit32.band(a, b), bit32.lshift(a, 1)
Removed for sandboxingio, package, loadstring, loadfile, dofile
Deprecated but still presentgetfenv, setfenv (they disable optimizations)
Not in Luaugoto / labels (Luau is based on Lua 5.1)
Reading stdin on Coddyio.read() works here - Coddy restores it on top of Luau
File extensionmain.luau (.lua also works)
Roblox-only, not core Luaugame, workspace, Instance.new, task.wait

Luau is Lua 5.1 plus a gradual type system - the language Roblox created and open-sourced. This Luau cheat sheet covers the parts that are *not* plain Lua: type annotations, typed tables, unions and literal types, generics, type assertions, and the syntax sugar Luau adds (+=, string interpolation, continue, if-then-else expressions). For everything the two languages share - tables, metatables, coroutines, the string library - keep the Lua cheat sheet open next to this one.

Every snippet here is standard Luau, runnable with the luau CLI and type-checkable with luau-analyze. Copy what you need, or try any of it live in the Luau playground - nothing to install. Learning the type system from scratch? Coddy's free interactive Luau course builds it up lesson by lesson.

Luau cheat sheet FAQ

Is this Luau cheat sheet free?
Yes. This Luau cheat sheet is completely free and needs no sign-up. Bookmark it for the next time you need the syntax for a union, a generic, or a typed table.
Does Luau have a += operator?
Yes. Unlike plain Lua, Luau supports compound assignment: +=, -=, *=, /=, //=, %=, ^=, and ..= for string concatenation. So hp += 10 is valid Luau (and valid Roblox script code), while in Lua 5.1 you have to write hp = hp + 10. Note that there is no ++ or -- in Luau.
What is the difference between Lua and Luau?
Luau is a superset of Lua 5.1 with a gradual type system. On top of types it adds string interpolation with backticks, compound assignment operators, continue, if-then-else expressions, floor division //, generalized iteration (for i, v in t do), and library functions like table.find, table.clone, and table.freeze. For sandboxing it removes loadstring, loadfile, dofile, and the io and package libraries, and it has no goto because it's based on 5.1. Most ordinary Lua code runs unchanged as Luau.
How do I turn on type checking in Luau?
Put a mode comment on the first line of the file: --!strict checks everything and infers aggressively, --!nonstrict (the default) only checks what you annotated, and --!nocheck turns checking off. Outside an editor, run luau-analyze main.luau to type-check without executing, and luau main.luau to run.
Do I write interface in Luau like in TypeScript?
No - Luau has no interface keyword. Object shapes are written as table types and given a name with type: type User = { name: string, age: number? }. Combine shapes with & instead of extends, and use export type to make one available to other modules.
Is this cheat sheet the same as Roblox scripting?
Everything here is core Luau - the language - so it applies to Roblox scripts and to standalone Luau alike. What's *not* here is the Roblox engine API (game, workspace, Instance.new, services, events), which is a library on top of the language and is documented by Roblox, not by Luau.
Where can I run these Luau snippets?
In the Luau playground - it runs the real luau interpreter in your browser, with stdin support, so you can paste any row from this page and press Run. For structured practice, the interactive Luau course covers the same material with exercises, projects, and a certificate.
Coddy programming languages illustration

Learn Luau with Coddy

GET STARTED