PiTyUs.Hire me

Getting started

The Lua you need for FiveM, from zero

Learn Lua for FiveM: variables and local, types, strings, if/else, for and while loops, functions, nil and truthiness, Lua 5.4 integers — plus the CfxLua extras: vectors, backtick hashes, CreateThread, Wait and json.

Updated 16 min readBy PiTyUs · FiveM developer

Overview

You do not need to master Lua to write FiveM scripts, but you do need the core of it: how values and variables behave, how to branch and loop, and how functions work. This guide teaches exactly that, with FiveM-flavoured examples, and then covers the extras FiveM adds on top of standard Lua 5.4.

Variables and local

Variableslua
local money = 500          -- a number
local name = 'Mike'        -- a string
local onDuty = false       -- a boolean
local vehicle = nil        -- nothing yet

money = money + 250        -- reassign
print(name, money)         -- Mike 750

Without local, a variable is global: visible to every file of the resource on that side, easy to overwrite by accident and slower to access. Make local a reflex. The one common exception is a config table like Config = {} that is deliberately shared between files.

The types you will meet

TypeExampleNotes
nilnil“No value”. Unset variables and missing table keys are nil.
booleantrue, false
number42, 3.5Lua 5.4 separates integers (42) and floats (42.0).
string'hello', "hi"Immutable text.
table{ 1, 2, x = 3 }The only data structure: arrays, maps, objects.
functionfunction() endFunctions are values you can store and pass.
vector3/4 (CfxLua)vector3(1, 2, 3)Positions and rotations, with maths built in.

Operators

OperatorMeaningExample
+ - * /Arithmetic (/ always returns a float)10 / 42.5
//Integer (floor) division10 // 42
%Remainder10 % 42
^Power2 ^ 38.0
== ~=Equal, not equaljob ~= 'police'
< > <= >=Comparisonmoney >= 100
and or notLogicif onDuty and not busy then
..Join strings'Hi ' .. name
#Length of a string or array#players

A handy idiom: local label = item.label or 'Unknown' returns the first value that is not nil or false — Lua’s way of setting a default.

if, for and while

Branchinglua
if money >= 1000 then
    print('rich')
elseif money > 0 then
    print('getting by')
else
    print('broke')
end
Loopslua
-- numeric: from 1 to 5
for i = 1, 5 do
    print(i)
end

-- counting down in steps
for i = 10, 0, -2 do print(i) end

-- over an array, in order
local jobs = { 'police', 'ambulance', 'mechanic' }
for index, job in ipairs(jobs) do
    print(index, job)
end

-- over any table (order not guaranteed)
local prices = { bread = 5, water = 2 }
for item, price in pairs(prices) do
    print(item, price)
end

-- while
local tries = 0
while tries < 3 do
    tries = tries + 1
end

Lua has no continue; use goto continue with a ::continue:: label, or restructure with if. break leaves a loop early.

Functions

Functionslua
local function fullName(first, last)
    return first .. ' ' .. last
end

-- Multiple return values are normal in Lua
local function minMax(a, b)
    if a < b then return a, b end
    return b, a
end

local lo, hi = minMax(9, 3)   -- 3, 9

-- Functions are values
local handlers = {
    greet = function(who) print('Hello ' .. who) end,
}
handlers.greet('Mike')

Multiple returns matter in FiveM: many natives return several values, for example local found, z = GetGroundZFor_3dCoord(x, y, 1000.0, false).

Strings

Common string worklua
local plate = '  ab12cd  '
plate = plate:upper():gsub('%s+', '')   -- 'AB12CD'

print(('%s has $%d'):format('Mike', 250))  -- Mike has $250
print(('%.2f'):format(3.14159))             -- 3.14
print(#'hello')                             -- 5
print(('police'):sub(1, 3))                -- pol
print(('a,b,c'):find(','))                  -- 2 2

('...'):format(...) is string.format, the tidy way to build messages. Note that gsub returns two values (the new string and a count) — wrap it in parentheses if you pass it straight to a function.

What FiveM adds: CfxLua

FeatureExampleWhy it matters
Vectorsvector3(x, y, z), #(a - b)Fast positions and distances
Backtick hashes`WEAPON_PISTOL`Hash computed at load time
ThreadsCreateThread(function() ... end)Run code in parallel with the game
WaitWait(1000)Pause a thread without freezing the game
JSONjson.encode(t), json.decode(s)Saving tables, talking to NUI and HTTP
Resource helpersGetCurrentResourceName()Know which resource you are

Threads and Wait are the part that most affects performance; they have their own guide: threads and Wait. Tables — the structure you will use most — are covered in Lua tables for FiveM.

Frequently asked questions

Is Lua hard to learn for FiveM?

No. It is one of the smallest mainstream languages. With the basics in this guide you can read most FiveM scripts; the harder part is learning the game’s natives and networking.

Why should I always use local?

Globals are shared across every file of the resource, easy to overwrite accidentally and slower to access. local keeps variables private and fast.

Do Lua arrays start at 0 or 1?

At 1. ipairs and # both assume arrays start at index 1.

What is the difference between pairs and ipairs?

ipairs walks an array from 1 in order and stops at the first gap. pairs visits every key of any table, in no guaranteed order.

Which Lua version does FiveM use?

Lua 5.4, with FiveM’s CfxLua extensions. Lua 5.3 was deprecated in June 2025.

Need this built, not just explained?

Ten years of FiveM work, from Lua to NUI

Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.

Related guides