Latent events: TriggerLatentServerEvent & TriggerLatentClientEvent
Big data should trickle, not slam. A regular TriggerServerEvent hands the whole payload (the data you are sending) to the network in one shot. For small messages that is fine. For big tables, image buffers, or character export blobs, that single burst can clog a player's connection long enough to time them out. A latent event sends the exact same data, but metered at a speed you set, in bytes per second, so the connection keeps breathing while the data flows across.
Build it
Make the resource folder
Inside your server's resources folder, create this folder:
resources/qu_latent_events
Create the files
Create this exact file layout:
resources/qu_latent_events/
fxmanifest.lua
server.lua
client.lua
Write fxmanifest.lua
Open fxmanifest.lua and paste this:
fx_version 'cerulean'
game 'gta5'
client_script 'client.lua'
server_script 'server.lua'
Older tutorials add a lua54 'yes' line here. As of June 2025 that setting is deprecated and ignored: Lua 5.4 is now the only Lua runtime, so you leave it out.
Write the lesson code
Open server.lua and paste this:
RegisterNetEvent('qu_latent_events:upload', function(payload)
-- `source` is the server id of the player who triggered this event.
-- It is only valid right here, so copy it into a local before anything else.
local src = source
-- SECURITY: any connected client can fire this event with any data,
-- not just the /latenttest command. Validate before you trust it.
if type(payload) ~= 'string' then return end -- reject non-string input
local size = #payload
if size > 6 * 1024 * 1024 then return end -- cap the size you accept
print('[qu_latent_events] server received ' .. size .. ' bytes from player ' .. src)
-- Acknowledge back down to the client, also as a latent stream.
TriggerLatentClientEvent('qu_latent_events:ack', src, 25000, size)
end)
Open client.lua and paste this:
RegisterCommand('latenttest', function()
local payload = string.rep('A', 20000) -- 20,000 bytes of filler
-- 25000 = stream this payload at 25,000 bytes per second.
TriggerLatentServerEvent('qu_latent_events:upload', 25000, payload)
print('[qu_latent_events] upload started (' .. #payload .. ' bytes at 25000 bps)')
end, false)
RegisterNetEvent('qu_latent_events:ack', function(size)
print('[qu_latent_events] client got ack: server saw ' .. size .. ' bytes')
end)
Start and test it
Open server.cfg and add this line:
ensure qu_latent_events
The ensure line makes the server start this resource every time it boots, but it only takes effect on the next boot. To load it now without rebooting, run this in your server console (the txAdmin Live Console, or the FXServer console window if you start the server directly):
restart qu_latent_events
Join the server, then open the chat box with T and run:
/latenttest
The client line prints first. About one second later (20,000 bytes at 25,000 bps), the server line lands in txAdmin Live Console. The ack then streams back down and the second F8 line appears. Three lines, two consoles, one full round trip.
Keep reading the full lesson
Sign in to start, then unlock every step of this lesson and the full FiveM School with a membership.
- How it works
- If something went wrong
- What you can do now
- Try it yourself
The remainder of Latent events is available to FiveM School members.