Skip to main content
TRACK B·BUILD REAL PRODUCTS·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.

Spawning entities safely

Everything you see in the game world -- every car, every pedestrian, every traffic cone -- is an entity. In this lesson you learn how to create one from code, track it in a table, and delete it cleanly so it never lingers in the world. This is the foundation every prop, NPC, and vehicle spawner is built on.

You'll ship
A client resource that loads a model, spawns a prop in front of you, tracks it in a registry table, auto-deletes it after 30 seconds, and clears everything on command and on restart.
Time
~25 minutes
You'll learn
What an entity is, the model load lifecycle, the CreateObject argument list, the registry-and-cleanup pattern, and how the same shape extends to peds and vehicles.
Prereqs
Comfortable with tables, the client/server split, and registering commands.
Quasar School: the ped system (part 1).
BEFORE YOU START

Build it

Make the resource folder

The server has one folder for this lesson.

Inside your server's resources folder, create this folder:

code
resources/qu_spawning_entities_safely

Create the files

Every file named in the manifest exists.

Create this exact file layout:

code
resources/qu_spawning_entities_safely/
fxmanifest.lua
client.lua

Write fxmanifest.lua

FiveM knows which file to load.

Open fxmanifest.lua and paste this:

code
fx_version 'cerulean'
game 'gta5'

client_script 'client.lua'

Older tutorials add a lua54 'yes' line here. As of June 2025 that setting is deprecated and ignored: Lua 5.4 is the only Lua runtime now, so you leave it out.

Write the lesson code

The topic is now represented by runnable code.

Open client.lua and paste this:

code
local objects = {}

local function loadModel(model)
if not IsModelInCdimage(model) or not IsModelValid(model) then
    return false
end

RequestModel(model)
local deadline = GetGameTimer() + 5000
while not HasModelLoaded(model) do
    if GetGameTimer() > deadline then return false end
    Wait(0)
end
return true
end

RegisterCommand('spawnbox', function()
local model = joaat('prop_boxpile_07d')
if not loadModel(model) then
    print('[qu_spawning_entities_safely] model is invalid or timed out')
    return
end

local coords = GetEntityCoords(PlayerPedId())
local object = CreateObject(model, coords.x + 2.0, coords.y, coords.z, false, false, false)
objects[object] = true
SetModelAsNoLongerNeeded(model)
print('[qu_spawning_entities_safely] spawned object ' .. object)

SetTimeout(30000, function()
    if DoesEntityExist(object) then
        DeleteEntity(object)
        objects[object] = nil
        print('[qu_spawning_entities_safely] timeout deleted object ' .. object)
    end
end)
end, false)

RegisterCommand('clearboxes', function()
local count = 0
for object in pairs(objects) do
    if DoesEntityExist(object) then DeleteEntity(object) end
    objects[object] = nil
    count = count + 1
end
print('[qu_spawning_entities_safely] registry cleared, removed ' .. count)
end, false)

AddEventHandler('onResourceStop', function(name)
if name ~= GetCurrentResourceName() then return end
for object in pairs(objects) do
    if DoesEntityExist(object) then DeleteEntity(object) end
end
end)

Start and test it

The expected proof appears in the F8 client console.

Open server.cfg and add this line:

code
ensure qu_spawning_entities_safely

Save, then run in the txAdmin Live Console:

code
restart qu_spawning_entities_safely

Now join the server, open the F8 console, and run this test. Spawn one box, spawn a second, then clear them. Watch a box appear two metres in front of you each time:

code
spawnbox
spawnbox
clearboxes

Then spawn one more box and do not clear it. Wait 30 seconds and watch it delete itself.

The handle numbers (73, 122, 145) will differ on your machine. They are runtime handles the game hands out, not fixed IDs. What matters is that every spawn prints a handle, clearboxes reports how many it removed, and an uncleared box prints its own timeout deleted line about half a minute later.

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
  • How it works
  • If something went wrong
  • What you can do now
  • Try it yourself

The remainder of Spawning entities safely is available to FiveM School members.