
Introduction to LUA-Scripting for FiveM
Lua is the scripting language that powers FiveM resource development. Whether you want to create custom jobs, modify existing scripts, or build entirely new gameplay systems, learning Lua is your gateway to FiveM development. This guide takes you from zero to writing your first functional FiveM script, covering Lua fundamentals, FiveM-specific APIs, and practical examples you can use immediately.
Why Lua for FiveM?
FiveM chose Lua as its primary scripting language for good reasons. Lua is lightweight, fast, and easy to learn. It was originally designed as an embedded scripting language for games, which makes it a natural fit for FiveM. If you have any programming experience — even basic JavaScript or Python — you will pick up Lua quickly. If Lua is your first language, its simple syntax makes it one of the friendlier starting points.
FiveM also supports C# and JavaScript for resource development, but the overwhelming majority of community resources are written in Lua. Learning Lua gives you access to the largest ecosystem of scripts, examples, and community support.
Lua Basics: Variables, Types, and Operators
Lua has a small set of data types and straightforward syntax. Here are the fundamentals:
Variables
Variables in Lua are global by default. Use the local keyword to create local variables, which is considered best practice for performance and avoiding naming conflicts:
local playerName = "John"local health = 100local isAlive = truelocal nothing = nil
Lua is dynamically typed — you do not declare variable types. A variable can hold any type of value and can change type during execution.
Data Types
- string — text values enclosed in quotes:
"hello" - number — both integers and decimals:
42,3.14 - boolean —
trueorfalse - nil — represents the absence of a value
- table — the only data structure in Lua, used for arrays, dictionaries, and objects
- function — functions are first-class values in Lua
Operators
Lua uses standard operators with a few unique ones:
- Arithmetic:
+,-,*,/,%(modulo),^(power) - Comparison:
==,~=(not equal — note this is different from most languages) - Logical:
and,or,not - String concatenation:
..(two dots, not +)
Functions
Functions are defined with the function keyword and are central to FiveM scripting:
local function greetPlayer(name) print("Welcome, " .. name .. "!")end
Functions can return values, accept multiple parameters, and be stored in variables or tables. In FiveM development, you will define functions constantly — for event handlers, commands, NUI callbacks, and utility logic.
Tables: The Swiss Army Knife
Tables are the only data structure in Lua, but they are incredibly versatile. They serve as arrays, dictionaries, objects, and more:
As an array:local weapons = {"pistol", "smg", "rifle"}print(weapons[1]) -- "pistol" (Lua arrays start at 1, not 0!)
As a dictionary:local player = { name = "John", job = "police", rank = 3 }print(player.name) -- "John"
The most important thing to remember: Lua arrays start at index 1, not 0. This trips up every developer coming from other languages.
Loops and Control Flow
Lua provides several loop constructs:
For loop (numeric):for i = 1, 10 do print(i)end
For loop (generic — iterating tables):for key, value in pairs(myTable) do print(key, value)end
While loop:while isRunning do -- do something Wait(1000)end
If/elseif/else:if health > 50 then print("Healthy")elseif health > 0 then print("Injured")else print("Dead")end
FiveM-Specific APIs
Now that you understand Lua basics, let us look at the FiveM-specific functions and concepts you will use constantly:
Events: The Communication System
Events are how different parts of your script (and different scripts) communicate. FiveM uses a client-server architecture where events pass data between the two sides:
Registering an event handler (server side):RegisterNetEvent("myScript:doSomething")AddEventHandler("myScript:doSomething", function(data) print("Received: " .. data)end)
Triggering a server event from client:TriggerServerEvent("myScript:doSomething", "hello server")
Triggering a client event from server:TriggerClientEvent("myScript:notify", source, "You received a message")
Always use RegisterNetEvent before AddEventHandler for network events. This registers the event as a valid network event and prevents exploits.
Commands
RegisterCommand("heal", function(source, args) local player = source -- heal logic here print("Player " .. player .. " healed")end, false) -- false = anyone can use, true = admin only
Threads (Citizen.CreateThread)
Threads are loops that run continuously in the background. They are essential for client-side gameplay logic:
Citizen.CreateThread(function() while true do Wait(1000) -- wait 1 second each loop -- check player status, update HUD, etc. endend)
Critical rule: Always include a Wait() in your threads. A thread without Wait() will freeze the game. Use Wait(0) for every-frame updates (use sparingly) and Wait(1000) or higher for periodic checks.
Native Functions
FiveM provides access to thousands of GTA V native functions. These control everything from player movement to weather, vehicles, weapons, and UI:
local ped = PlayerPedId() -- get the player characterlocal coords = GetEntityCoords(ped) -- get positionlocal health = GetEntityHealth(ped) -- get healthSetEntityCoords(ped, 100.0, 200.0, 30.0) -- teleport
The FiveM native reference at docs.fivem.net/natives is your best friend. Bookmark it — you will reference it constantly.
Client vs Server Scripts
Understanding the client-server split is fundamental to FiveM development:
| Aspect | Client Script | Server Script |
|---|---|---|
| Runs on | Player computer | Server machine |
| Access to | GTA natives, player ped, UI | Database, all players, server state |
| Trust level | Untrusted (can be modified) | Trusted (server-authoritative) |
| Use for | UI, visual effects, input, local gameplay | Data storage, validation, economy, permissions |
| File suffix convention | cl_*.lua or client/*.lua | sv_*.lua or server/*.lua |
Golden rule: Never trust the client. All important logic (money, inventory, permissions) must be validated on the server. The client handles presentation and user interaction; the server handles game state and data.
fxmanifest.lua Explained
Every FiveM resource needs a fxmanifest.lua file that tells the server what the resource contains:
fx_version "cerulean"game "gta5"name "my-first-script"description "A simple example resource"version "1.0.0"client_scripts { "client/main.lua",}server_scripts { "server/main.lua",}shared_scripts { "config.lua",}
Key fields: fx_version should be "cerulean" (the current version). client_scripts run on the player, server_scripts run on the server, and shared_scripts run on both. You can also define dependencies to specify resources that must be loaded before yours.
Your First Script: A Heal Command
Let us build a complete, functional script from scratch. This script adds a /heal command that restores the player health:
fxmanifest.lua:fx_version "cerulean"game "gta5"name "my-heal-script"server_scripts { "server.lua" }client_scripts { "client.lua" }
server.lua:RegisterCommand("heal", function(source) TriggerClientEvent("myHeal:doHeal", source) print("Healing player " .. source)end, false)
client.lua:RegisterNetEvent("myHeal:doHeal")AddEventHandler("myHeal:doHeal", function() local ped = PlayerPedId() SetEntityHealth(ped, GetEntityMaxHealth(ped))end)
Place this in your resources folder, add ensure my-heal-script to server.cfg, and restart. Type /heal in chat and your health will be fully restored.
Debugging Tips
- Use print() liberally —
print()outputs to the server console (server scripts) or F8 console (client scripts). It is your primary debugging tool. - Check the F8 console — Press F8 in-game to see client-side errors and print output. Most script errors will appear here with line numbers.
- Server console — Server-side errors appear in your server terminal. Always keep it visible during development.
- Type checking — Use
type(variable)to verify what type a variable actually is. Many bugs come from unexpected nil values. - Lua error messages — Learn to read Lua error messages. They tell you the file, line number, and nature of the error. The most common ones are "attempt to index a nil value" (accessing a property on nil) and "attempt to call a nil value" (calling a function that does not exist).
Useful Resources for Learning
- FiveM Documentation —
docs.fivem.net— official native reference and guides - Programming in Lua — The official Lua book, available free online at lua.org/pil
- QBCore Documentation — If using QBCore, their docs explain framework-specific functions
- Overextended Documentation — For ox_lib and QBOX development
- FiveM Forums and Discord — Active community for questions and script sharing
- GitHub — Search for open-source FiveM resources to study real-world code
Final Thoughts
Learning Lua for FiveM is a rewarding journey that opens up unlimited possibilities for your server. Start with simple scripts like commands and event handlers, study existing open-source resources to see how experienced developers structure their code, and gradually take on more complex projects. The FiveM community is welcoming to new developers, so do not hesitate to ask questions in forums and Discord servers. Every expert FiveM developer started exactly where you are now.
Ready-Made FiveM Scripts to Learn From on VertexMods
Once you know Lua, explore these well-coded FiveM scripts on VertexMods. They are great references for studying real-world script architecture:
- jobs-creator-7 — 60€ — Jobs Creator — extensible job framework
- drugs-creator — 50€ — Drugs Creator — advanced drug system
- robbery-creator — 65€ — Robbery Creator — configurable heist system
- restaurant-system — 44€ — Restaurant System — multi-mechanic job script
Stay in the Loop
Get the latest FiveM tutorials, mod releases, and exclusive updates delivered to your inbox.
No spam. Unsubscribe anytime.