Getting started
Write your first FiveM script, step by step
A beginner FiveM scripting tutorial: create a resource, write fxmanifest.lua, add a /car command that spawns a vehicle with RequestModel and CreateVehicle, talk to the server, and test it with ensure and the F8 console.
Overview
Reading about FiveM scripting only goes so far; the moment it clicks is when your own command does something in the game. In this tutorial you build a small but complete resource from an empty folder: a /car command that spawns any vehicle, a message sent to the server, and a log line printed back. Every file is shown in full, and every line is explained.
What you need
- A FiveM server you can restart — a local one on your own PC is ideal; see a local development server.
- A code editor; VS Code with a Lua extension is the common choice — see VS Code setup for FiveM.
- Ten minutes.
01Step 1: create the resource
Inside your server’s resources folder, create a folder named my_first with three files:
resources/
└── my_first/
├── fxmanifest.lua
├── client.lua
└── server.luafx_version 'cerulean'
game 'gta5'
name 'my_first'
description 'My first FiveM resource'
client_script 'client.lua'
server_script 'server.lua'The manifest tells FiveM this folder is a resource, that it targets GTA V, and which file runs where. What a FiveM resource is explains every directive.
02Step 2: the client script
This runs in each player’s game. It registers a /car command that takes a model name, loads the model, spawns the vehicle in front of the player and puts them in the driver’s seat.
RegisterCommand('car', function(source, args)
local modelName = args[1] or 'adder'
local model = joaat(modelName)
-- 1. Is it a real vehicle model?
if not IsModelInCdimage(model) or not IsModelAVehicle(model) then
print(('"%s" is not a vehicle model'):format(modelName))
return
end
-- 2. Load it (with a timeout so we never wait forever)
RequestModel(model)
local timeout = GetGameTimer() + 5000
while not HasModelLoaded(model) do
if GetGameTimer() > timeout then
print('model took too long to load')
return
end
Wait(0)
end
-- 3. Spawn it where the player stands, facing the same way
local ped = PlayerPedId()
local pos = GetEntityCoords(ped)
local heading = GetEntityHeading(ped)
local vehicle = CreateVehicle(model, pos.x, pos.y, pos.z, heading, true, false)
-- 4. Seat the player and tidy up
SetPedIntoVehicle(ped, vehicle, -1) -- -1 is the driver seat
SetModelAsNoLongerNeeded(model)
-- 5. Tell the server
TriggerServerEvent('my_first:spawned', modelName)
end, false)| Line | What it does |
|---|---|
joaat(modelName) | Turns the text name into the model hash the game uses. |
IsModelInCdimage / IsModelAVehicle | Checks the model exists and is a vehicle, so typos do not hang. |
RequestModel + HasModelLoaded | Asks the game to load the model and waits until it is in memory. |
Wait(0) | Yields one frame so the game keeps running while you wait. |
CreateVehicle(..., true, false) | Spawns a networked vehicle so other players can see it. |
SetPedIntoVehicle(ped, vehicle, -1) | Puts the player in the driver seat. |
SetModelAsNoLongerNeeded | Lets the game unload the model when it is not in use. |
TriggerServerEvent | Sends a message to the server script. |
03Step 3: the server script
RegisterNetEvent('my_first:spawned', function(modelName)
local src = source
local name = GetPlayerName(src)
print(('%s (id %d) spawned a %s'):format(name, src, tostring(modelName)))
end)RegisterNetEvent allows the event to be triggered from clients, and source is the ID of the player who sent it. Store it in a local immediately — its value changes as soon as your handler waits. More in FiveM events explained.
04Step 4: run it
- Add
ensure my_firstto server.cfg, after your framework if you have one. - Start (or restart) the server and join it.
- Open chat (T) and type
/car sultan. - Check the server console for the line
… spawned a sultan. - Change something in client.lua, then type
ensure my_firstin the server console (or F8 with permission) to reload.
Where to go from here
This script is fine for a private test server. Before putting anything like it on a public server, three things change:
- Anyone can spawn anything — restrict the command with an ACE permission as shown in commands and key mapping.
- Spawning on the server with OneSync is more robust — see server-side entities.
- On a framework server, vehicles belong in the garage system, not a free command.
To understand the language itself, continue with Lua basics for FiveM.
Frequently asked questions
How do I make a FiveM script?
Create a folder in resources, add an fxmanifest.lua that lists your client and server scripts, write the scripts, add ensure foldername to server.cfg and restart the server.
Why does my car not spawn?
Most often the model was not loaded before CreateVehicle, or the model name is wrong. Request the model and wait for HasModelLoaded, and check the name with IsModelInCdimage.
Do I need to restart the whole server to test changes?
No. Type ensure yourresource in the server console to restart just that resource.
Where do print() messages appear?
Client-side prints appear in the F8 console in game; server-side prints appear in the server console or txAdmin’s live console.
What does -1 mean in SetPedIntoVehicle?
It is the seat index for the driver. 0 is the front passenger, 1 and 2 the rear seats.
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
- Getting startedThe Lua you need for FiveM, from zeroAlways declare variables with local. Lua has nil, booleans, numbers, strings, tables and functions; only nil and false are falsy (0 and empty strings are true). Use if/elseif/else, numeric for i = 1, 10, for k, v in pairs(t) and while. Concatenate strings with .. and format with string.format. CfxLua adds vector3, backtick hashes, CreateThread and Wait.
- Getting startedWhat a FiveM resource is, and how the server loads itA resource is a folder inside resources/ containing an fxmanifest.lua. The manifest declares the format (fx_version 'cerulean', game 'gta5'), which scripts run on the client, the server or both, which extra files clients download, and what the resource depends on. The server starts it when server.cfg says ensure foldername.
- EngineeringEvents in FiveM: how resources and players talkHandle events with AddEventHandler(name, fn); add RegisterNetEvent(name) (or use RegisterNetEvent(name, fn)) to allow the event to arrive over the network. TriggerEvent fires locally on the same side, TriggerServerEvent sends from a client to the server, and TriggerClientEvent(name, target, ...) sends from the server to one player (target = player ID) or everyone (-1). On the server, source is the sending player.
- Getting startedWhere FiveM errors appear and how to read themClient script errors appear in the F8 console in game; server script errors appear in the server console (or txAdmin’s Live Console). A SCRIPT ERROR: @resource/client.lua:23: attempt to index a nil value (local 'data') line tells you the resource, the file, the line number and what went wrong. Read the first error, not the last — later errors are often consequences of the first.