Getting started
Client-side vs server-side in FiveM
What belongs in a FiveM client script and what belongs on the server: rendering, input and local effects vs money, inventory and database — with the rule that keeps your server secure and working examples of both sides talking.
Overview
Every FiveM script is split between two computers: the player’s game (the client) and your server. Getting the split right is what separates a script that works from one that works until the first cheater joins. The rule is simple once you see it, and it applies to every framework and every language.
The picture
Imagine 64 players. Your server script runs once. Your client script runs 64 times, once inside each player’s game, and each copy only knows about its own player and the world near them. That is the whole difference, and it explains the rest.
| Client script | Server script | |
|---|---|---|
| Runs on | Each player’s PC | Your server, once |
| Sees | Its own player and nearby world | All players and the database |
| Can do | Draw, read keys, play animations, NUI | Save data, pay money, give items, kick/ban |
| Trust | None — the player controls it | Full — you control it |
| Typical files | client/main.lua | server/main.lua |
What belongs on the client
- Drawing markers, text, 3D prompts and HUD elements.
- Reading key presses and opening menus or NUI.
- Playing animations, sounds and particle effects for the local player.
- Checking whether the player is near something, to decide when to show a prompt.
- Spawning purely local, cosmetic things only this player sees.
What belongs on the server
- Money, bank balances, items and inventory changes.
- Reading and writing the database.
- Jobs, grades, licences and permissions.
- Rewards for completing anything — the server decides whether it was completed.
- Cooldowns and limits that must hold for everyone.
- Discord or webhook logging (so API keys never reach players).
01How the two sides talk
A delivery job, done properly: the client reports what the player did, the server checks it and pays.
local DROP = vector3(-1037.8, -2737.4, 20.2)
CreateThread(function()
while true do
local sleep = 1000
local pos = GetEntityCoords(PlayerPedId())
if #(pos - DROP) < 3.0 then
sleep = 0
-- show a prompt here
if IsControlJustPressed(0, 38) then -- E
TriggerServerEvent('delivery:complete')
end
end
Wait(sleep)
end
end)local DROP = vector3(-1037.8, -2737.4, 20.2)
local PAY = 250
local lastDelivery = {}
RegisterNetEvent('delivery:complete', function()
local src = source
local ped = GetPlayerPed(src)
-- 1. Is the player really there? (OneSync gives the server positions)
if #(GetEntityCoords(ped) - DROP) > 10.0 then return end
-- 2. Cooldown so it cannot be spammed
local now = os.time()
if lastDelivery[src] and now - lastDelivery[src] < 60 then return end
lastDelivery[src] = now
-- 3. The server decides the amount
-- e.g. exports.ox_inventory:AddItem(src, 'money', PAY)
print(('paid %s to %d'):format(PAY, src))
end)
AddEventHandler('playerDropped', function()
lastDelivery[source] = nil
end)Notice what the client sends: nothing but “I think I finished”. Position, cooldown and amount are all decided on the server. Events are explained fully in FiveM events, and the security side in securing server events.
What the server can know about the world
With OneSync enabled — the default on modern servers — the server tracks entities, so natives like GetPlayerPed, GetEntityCoords and GetVehiclePedIsIn work in server scripts. That is what makes the distance check above possible. Without OneSync the server knows very little, and validation is much harder. Entity ownership and network IDs explains how entities are shared.
Frequently asked questions
What is the difference between client-side and server-side in FiveM?
Client-side code runs on each player’s game and handles what they see and press. Server-side code runs once on the server and handles money, items, the database and permissions.
Can players see my server scripts?
No. Server scripts are never sent to players. Client and shared scripts are downloaded to every player’s PC, so assume players can read them.
Should I give money on the client?
Never. The client can only ask; the server checks the request and changes the money.
How does a client script talk to the server?
With TriggerServerEvent('name', ...) on the client and RegisterNetEvent('name', handler) on the server. The server replies with TriggerClientEvent.
Where should I put my Discord webhook URL?
In a server-only file or a server convar. Anything in client or shared scripts is visible to players.
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
- EngineeringEvents in FiveM: how resources and players talkHandle events with AddEventHandler(name, fn); add RegisterNetEvent(name) (or use RegisterNetEvent(name, fn)) to allow the event to arrive over the network. TriggerEvent fires locally on the same side, TriggerServerEvent sends from a client to the server, and TriggerClientEvent(name, target, ...) sends from the server to one player (target = player ID) or everyone (-1). On the server, source is the sending player.
- EngineeringWriting server events that cannot be abusedAny client can call any event you registered with RegisterNetEvent, with any arguments. In each handler: copy source into a local, check argument types and ranges, re-derive everything from server state (prices, amounts, rewards), verify the player can do this now (distance, job, item, cooldown), and log refusals. Events only other server scripts should use are registered with AddEventHandler alone, so clients cannot trigger them.
- Getting startedWhat a FiveM resource is, and how the server loads itA resource is a folder inside resources/ containing an fxmanifest.lua. The manifest declares the format (fx_version 'cerulean', game 'gta5'), which scripts run on the client, the server or both, which extra files clients download, and what the resource depends on. The server starts it when server.cfg says ensure foldername.
- EngineeringEntity ownership, handles and network IDs in FiveMEntity handles are local to each client and to the server; never send them over events. Convert to a network ID with NetworkGetNetworkIdFromEntity, send the ID, and convert back with NetworkGetEntityFromNetworkId (or NetToVeh/NetToPed/NetToObj on the client). Each networked entity has an owner that simulates it; other clients must request control before changing it, and ownership migrates when the owner leaves.