PiTyUs.Hire me

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.

Updated 12 min readBy PiTyUs · FiveM developer

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 scriptServer script
Runs onEach player’s PCYour server, once
SeesIts own player and nearby worldAll players and the database
Can doDraw, read keys, play animations, NUISave data, pay money, give items, kick/ban
TrustNone — the player controls itFull — you control it
Typical filesclient/main.luaserver/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.

client/main.lualua
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)
server/main.lualua
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.

Shared scripts and configs

A shared_script runs on both sides. It is ideal for configuration both sides need, such as coordinates or item names. Remember that a shared config is sent to every player: never put webhook URLs, API keys or database credentials in it — keep those in server-only files or server convars, as described in convars.

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