Skip to main content
TRACK B·FIVEM FUNDAMENTALS·Verified June 2026 · Lua 5.4 · ox_lib 3.x
Learning with an AI assistant?
Copies this lesson plus 2026 ground rules (no lua54 'yes', Cfx.re Portal, correct callback signatures) as a ready-to-paste mentor prompt.

How to use State Bags

A State Bag is a sticky note attached to a player or entity that every resource can read. You write a value once, and FiveM copies it everywhere automatically. No events, no asking around. Need to know a player's job, hunger, or radio channel? Just read their note. In 2026 this is the standard way to share data that lots of resources need but nothing breaks if it's a beat late.

You'll build
A resource that sets, gets, and reacts to State Bag changes - sharing data between resources without events.
Time
~20 minutes
You need
A local FiveM server, one resource you can edit.
You'll learn
Player vs entity State Bags, setting and getting values, reacting to changes with handlers, and when to use State Bags vs events.
BEFORE YOU START

Build it

Create the resource

A new resource folder with the basic files.
code
resources/qu_statebag_demo/
fxmanifest.lua
server.lua
client.lua
code
fx_version 'cerulean'
game 'gta5'

server_script 'server.lua'
client_script 'client.lua'

Set a State Bag value (server)

The player's State Bag has a 'job' key.

Write a value to a player's note. We do this on the server because the server is the boss of player state:

code
-- Set a State Bag value for a player
local playerId = 1  -- replace with actual player ID
local playerState = Player(playerId).state

playerState:set('job', 'police', true)  -- true = replicate to all clients
print(('Set player %s job to police'):format(playerId))

That third argument (true) decides who gets to see the value. Replication just means "copy it out to every client." Pass true and all players can read it. Pass false and it stays server-only, like a private note.

Read a State Bag value (client)

Any client can read the player's job.

Now read the note back. Any client can read another player's State Bag - first turn the server ID into a client ID, then grab the value:

code
-- Read another player's State Bag
local targetId = GetPlayerFromServerId(1)  -- server ID → client ID
local job = Player(targetId).state.job
print(('Player 1 job: %s'):format(job or 'not set'))

-- Read your own State Bag
local myJob = LocalPlayer.state.job
print(('My job: %s'):format(myJob or 'not set'))

Reading your own note is even easier: LocalPlayer.state is always you, so there's no ID lookup to do.

React to State Bag changes

Your code fires automatically when a value changes.

Best part: you don't have to keep checking the note. A change handler is code that FiveM runs for you the moment a value changes. Set one up for job:

code
-- Handler fires every time 'job' changes on any player
AddStateBagChangeHandler('job', nil, function(bagName, key, value)
local playerId = GetPlayerFromStateBagName(bagName)
if playerId == 0 then return end  -- bagName is not a player
print(('Player %s job changed to: %s'):format(playerId, value))
end)

It fires on every change, all on its own. No loop checking the value over and over, no event to trigger.

Keep reading the full lesson

Sign in to start, then unlock every step of this lesson and the full FiveM School with a membership.

Still ahead in this lesson
  • Common failures

The remainder of How to use State Bags is available to FiveM School members.