FiveM resources can use CfxLua, a modified Lua 5.4 runtime, for client and server scripts. A current resource starts with fxmanifest.lua, lists the files that each context loads, and keeps authoritative decisions such as permissions, money and inventory on the server.
The old __resource.lua manifest and the lua54 'yes' switch are deprecated for new work. Cfx.re states that Lua 5.3 support ended in June 2025 and current scripts use Lua 5.4.
Create a minimal resource
Inside your server-data resources directory, create [local]/hello_fivem. The brackets group resources; the resource itself is the hello_fivem directory.
fxmanifest.lua:
fx_version 'cerulean'
game 'gta5'
author 'Your name'
description 'Small CfxLua learning resource'
version '1.0.0'
client_script 'client.lua'
server_script 'server.lua'
client.lua:
RegisterCommand('mycoords', function()
local coords = GetEntityCoords(PlayerPedId())
print(('x=%.2f y=%.2f z=%.2f'):format(coords.x, coords.y, coords.z))
end, false)
server.lua:
AddEventHandler('onResourceStart', function(resourceName)
if resourceName ~= GetCurrentResourceName() then
return
end
print(('[%s] started'):format(resourceName))
end)
The manifest and runtime behaviour are documented in the official resource manifest reference En CfxLua guide.
Understand client and server contexts
A client script runs separately for each connected player and can call game-facing natives such as PlayerPedId En GetEntityCoords. A server script coordinates shared state, persistence and authorization. Values supplied by a client are inputs, not proof.
Gebruik AddEventHandler for events that should stay in one context. Use RegisterNetEvent only when an event must cross the client/server boundary. The official Secure Your Events guide explains why every networked action must validate the player’s current server-side permission and state.
Avoid blocking the scheduler
CfxLua scripts are cooperatively scheduled. A loop that never yields can freeze its script context. When a loop must wait, use Wait with a delay appropriate to the job, and do not poll a database or HTTP endpoint every frame. Prefer events and state changes over permanent polling.
Use exports for a clear resource boundary
An export exposes a named function to another resource. Define it explicitly and document its arguments and return value:
exports('formatPlayerLabel', function(serverId, playerName)
return ('[%d] %s'):format(serverId, playerName)
end)
Another Lua resource can call it as exports.hello_fivem:formatPlayerLabel(id, name). Do not use an export to bypass permission or ownership checks.
Run and test the resource
- Back up the resource you are replacing, if any.
- In the server console, run
refreshen danensure hello_fivem. - Check the server console for the start message.
- Connect to the development server, open F8 and run
mycoords. - Restart the server to confirm the resource is included in the normal startup order.
The supported resource commands are listed in the official server-command reference. Continue with the official first Lua script tutorial before adding framework or database dependencies.
