Which file runs where
Last lesson you learned the idea: some code runs on the player's PC, some runs on the host machine, and the host is the one you can trust. This lesson makes that idea concrete. Every resource you ever build has files that run on the player's PC, files that run on the host, and files that both can read. You decide which is which by one word in the manifest. Get that word right and your code lands in the right place. Get it wrong and players can cheat. By the end you will know exactly where any line of code belongs.
The three kinds of files
Open any real FiveM resource and you will see its files sorted into three buckets. The bucket a file lives in decides where it runs. There are only three, and you already met the idea behind them.
Vocabulary
- client_script
- A file that runs on each player's own PC. There is a separate copy running inside every connected player's game. Client code can see the game world and draw on the screen: the player's character, the camera, on-screen text, key presses. The catch is that it runs on the player's machine, so a cheater can read it and change it.
- server_script
- A file that runs on the host machine, the one computer that everyone connects to. There is only one copy and players never see it. Because the host is yours, server code is trusted: this is where money, items, and permissions are decided.
- shared_script
- A file loaded by BOTH the client and the server. Use it for plain data that both sides need to agree on, like a config table of prices or job names. Not for secrets, and not for deciding anything important.
- source of truth
- The one place that holds the real answer. In FiveM that place is the server. When the client and the server disagree about how much money a player has, the server wins, because the server is the source of truth.
A handy picture: think of an online shop. The website on your phone is the client. It shows you products and lets you tap "buy", but it does not actually hold your bank balance. The shop's computer in a data center is the server. It checks your card, takes the money, and ships the box. Your phone only asks; the shop's computer decides. FiveM works the same way. The player's PC asks, the host decides.
Why the split exists
You saw the reason in the last mental-model lesson, so this is a quick refresher, not new ground.
The client runs on the player's own computer. That means the player can open the files, read them, and change them. You cannot stop this. So you can never trust anything the client says or does. A cheater will edit their client code to give themselves free items, infinite money, or god mode.
The server runs on your machine. Players cannot see it or touch it. So the server is the only side you can trust. The rule that falls out of this is simple: the client asks, the server decides. The client is the part the player can cheat, so it never gets the final say on anything that matters.
That is the whole reason the three buckets exist. The split is not for tidiness. It is the line between "code a cheater controls" and "code you control".
How it maps in the manifest
You met fxmanifest.lua last lesson. It is the small file that tells FiveM what is in your resource. The way you put a file into one of the three buckets is by listing it under the matching keyword. Here is a complete tiny manifest:
fx_version 'cerulean'
game 'gta5'
client_script 'client.lua'
server_script 'server.lua'
shared_script 'config.lua'Read it top to bottom. client_script 'client.lua' says "send client.lua to every player's PC". server_script 'server.lua' says "keep server.lua on the host only". shared_script 'config.lua' says "load config.lua on both sides". The keyword on the left is the only thing that decides where the file on the right ends up.
On disk, those three files sit in one folder next to the manifest:
my_resource/
fxmanifest.lua the manifest that sorts the files
client.lua runs on each player's PC
server.lua runs on the host, trusted
config.lua loaded by both sidesThere is nothing special about the file names. You could call them anything. What matters is which keyword you list each one under in the manifest. Move server.lua to client_script by mistake and now your trusted code is sitting on the player's PC for anyone to read.
The one rule you never break
Everything in this lesson collapses into a single rule. If you remember nothing else, remember this one.
A quick way to test any line you write: ask yourself "could a cheater abuse this if they controlled it?" If the answer is yes, that line belongs on the server.
See it
Here is the smallest possible example of the rule in action. A player presses a key, the client asks the server to do something, and the server is the one that actually decides and acts. Watch which file each line lives in.
-- client.lua (runs on the player's PC)
RegisterCommand('giveme', function()
-- The client does NOT give the item itself.
-- It only sends a request to the server and lets the server decide.
TriggerServerEvent('shop:requestItem', 'bread')
end)-- server.lua (runs on the host, trusted)
RegisterNetEvent('shop:requestItem', function(itemName)
local playerId = source -- who asked. the server knows this for sure.
-- The server decides. It could check money, permissions, distance here.
print('Player ' .. playerId .. ' asked for: ' .. itemName)
-- ... only now would it actually give the item ...
end)Line by line, by file:
- In
client.lua,TriggerServerEvent('shop:requestItem', 'bread')is the client asking. It does not give anything. It sends a message to the server that says "this player wants bread". ATriggerServerEventis the client's way of talking to the host. - In
server.lua,RegisterNetEventlistens for that message. When it arrives, the function runs on the host.local playerId = sourcerecords which player asked. The server cannot be lied to about this; it knows who connected. - The
printlands in the server console, the host's log, becauseserver.luaruns on the host. Only after its checks would the server hand over the item.
Notice the client never touches the item. It only asks. That is the rule made real: client asks, server decides.
Common beginner mistakes
These three trip up almost everyone at the start. Each one comes straight from putting code in the wrong bucket.
| Symptom | Fix |
|---|---|
attempt to call a nil value (global 'GetPlayerPed') | You called a client-only native inside a server_script. Things like reading the player's character or drawing on screen only exist on the client. Move that line into your client.lua, or rethink whether the server should be touching the screen at all (it should not). |
A player's money or item count goes back to normal after they reconnect, or a cheater gets free items | You changed money or gave an item in client.lua. The client only holds a display copy and the player can edit that code. Do the real change in server.lua so the trusted side owns it and saves it. |
attempt to index a nil value (global 'Config') | Your config was loaded on only one side. If client.lua reads Config but config.lua is listed as a server_script, the client never got it. List the config as a shared_script so both sides load it. |
A player buys an item. Which file subtracts the money, and why?
The server_script subtracts the money. Money is important, so it must be decided on the side the player cannot edit. The client_script only sends a request ("I want to buy this") and shows the result. If the client subtracted the money itself, a cheater would delete that line from their own copy and get the item for free, because the client runs on their PC. The server is the source of truth for money, so the server makes the change.
Try it yourself
What you can do now
- Name the three kinds of script: client_script runs on each player's PC, server_script runs on the trusted host, shared_script loads on both.
- Explain why the split exists: the client runs on the player's machine so it cannot be trusted, and the server is the source of truth.
- Read a manifest and say where each file will run based on its keyword.
- Apply the one rule: important checks (money, items, permissions) happen on the server; the client only shows and requests.
- Spot the three classic mistakes: a client-only native in server code, a money change in client code, and a config loaded on only one side.
Now you know where code runs. Next you learn how to actually run it and watch it work: ensure the resource, restart it after an edit, and read the console for your output. That loop is how you build everything from here. Continue to "The dev loop: ensure, restart, read the console".