PiTyUs.Hire me

Engineering

Events in FiveM: how resources and players talk

FiveM events explained: local vs network events, RegisterNetEvent and AddEventHandler, TriggerEvent, TriggerServerEvent and TriggerClientEvent (and -1 for everyone), the source variable, built-in events, latent events and event security.

Updated 14 min readBy PiTyUs · FiveM developer

Overview

Events are the nervous system of a FiveM server. A client tells the server a player pressed E; the server tells every client a door unlocked; one resource tells another a job changed. The API is only a handful of functions, but the difference between a local event, a network event and a network event anyone can trigger is exactly where both bugs and exploits live.

Local and network events

FunctionCalled onReaches
TriggerEvent(name, ...)Client or serverHandlers on the same side only
TriggerServerEvent(name, ...)ClientThe server
TriggerClientEvent(name, target, ...)ServerOne player (target = ID) or all (-1)
TriggerLatentServerEvent(name, bps, ...)ClientThe server, rate-limited for big payloads
TriggerLatentClientEvent(name, target, bps, ...)ServerClient(s), rate-limited

A local event is a message between resources on the same machine. A network event crosses from client to server or back. The receiving side must have registered the event as a network event, otherwise a network trigger is ignored — that registration is a small safety barrier.

Registering and handling

server.lualua
-- Short form: register as a net event and add the handler
RegisterNetEvent('bank:deposit', function(amount)
    local src = source
    -- validate, then act
end)

-- Long form, equivalent
RegisterNetEvent('bank:withdraw')
AddEventHandler('bank:withdraw', function(amount)
    local src = source
end)

-- A purely local event between resources on the server
AddEventHandler('myjob:shiftStarted', function(playerId)
    print('shift started', playerId)
end)

Sending events

client.lualua
TriggerServerEvent('bank:deposit', 500)

RegisterNetEvent('bank:updated', function(balance)
    print('new balance', balance)
end)
server.lualua
-- To the player who asked
TriggerClientEvent('bank:updated', src, newBalance)

-- To everyone
TriggerClientEvent('weather:changed', -1, 'RAIN')

Arguments can be numbers, strings, booleans and tables (serialised with msgpack). Functions and entity handles do not travel meaningfully — send network IDs for entities, as explained in entity ownership and network IDs.

Built-in events worth knowing

EventSideFires when
playerConnectingServerA player starts connecting (deferrals, whitelists)
playerJoiningServerA player has joined and has a server ID
playerDroppedServerA player leaves — clean up their data here
onResourceStart / onResourceStopBothAny resource starts or stops (check the name)
onClientResourceStartClientA resource starts on this client
gameEventTriggeredClientGame events such as damage (CEventNetworkEntityDamage)
Cleaning up on stoplua
AddEventHandler('onResourceStop', function(resourceName)
    if resourceName ~= GetCurrentResourceName() then return end
    -- delete spawned entities, remove blips, close NUI
end)

Latent events for large payloads

Normal net events are sent immediately and are meant for small messages. Sending large tables — a whole inventory, a long list of vehicles — through them can stall the connection. Latent events split the payload and send it at the bandwidth you specify, in bytes per second:

server.lualua
TriggerLatentClientEvent('garage:list', src, 50000, vehicles) -- ~50 KB/s

Better still, avoid large payloads: send only what changed, or let the client ask for one page at a time. For ongoing state, state bags often replace events entirely.

Event security in one paragraph

Every event registered with RegisterNetEvent on the server can be triggered by any connected client, at any time, with any arguments — mod menus list them and fire them in a loop. So a server handler must decide for itself whether the request is allowed: is this player the right job, close enough, not on cooldown, asking for a sensible amount? Never accept an amount of money, an item or a target player ID from a client without checking it. The full checklist is in securing server events and event rate limiting.

Naming events

  • Prefix with your resource: garage:store, bank:deposit. It avoids collisions with other resources.
  • Use a direction or verb that makes the flow obvious: server: / client: prefixes are also common.
  • Do not give net events names that describe privileged actions (admin:giveMoney) without strict checks — they are the first thing cheaters try.

Frequently asked questions

What is the difference between TriggerEvent and TriggerServerEvent?

TriggerEvent only reaches handlers on the same side (client to client scripts, or server to server scripts). TriggerServerEvent sends from a client to the server.

How do I send an event to all players?

TriggerClientEvent('eventName', -1, ...) from the server.

What is source in FiveM?

In a server event handler, source is the server ID of the player who triggered it. Copy it to a local variable immediately, because it can change after any wait.

Why is my event not received?

The receiving side did not call RegisterNetEvent for that name, the name differs by a character, or the resource with the handler is not started.

Can players trigger my server events?

Yes. Any registered net event can be triggered by a client with arbitrary arguments. Validate every request on the server.

When should I use latent events?

For large payloads, so the transfer is spread out instead of blocking the connection.

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