Frameworks
Creating zones in FiveM with ox_lib (and PolyZone)
Detect when players enter areas in FiveM: ox_lib zones (box, sphere, poly) with onEnter, onExit and inside, the /zone creator command, PolyZone for older resources, performance tips, server-side checks, and choosing between zones, points and targets.
Overview
Garages, safe zones, drug fields, job areas and speed limits all ask the same question: is the player inside this area right now? Zone libraries answer it efficiently and give you enter and exit events, so your script reacts once instead of measuring distances every frame.
The three zone shapes
| Shape | Defined by | Good for |
|---|---|---|
| Sphere | coords, radius | Points of interest, round areas |
| Box | coords, size, rotation | Rooms, parking bays, buildings |
| Poly | points (vec3 list), thickness | Irregular areas — fields, beaches, districts |
ox_lib zones in code
local safe = lib.zones.poly({
points = {
vec3(-1040.0, -2750.0, 20.0),
vec3(-1000.0, -2710.0, 20.0),
vec3(-960.0, -2750.0, 20.0),
vec3(-1000.0, -2790.0, 20.0),
},
thickness = 12.0,
debug = false,
onEnter = function()
lib.notify({ title = 'Safe zone', description = 'Weapons disabled', type = 'inform' })
end,
onExit = function()
lib.notify({ title = 'Safe zone', description = 'You left the safe zone', type = 'warning' })
end,
inside = function()
DisablePlayerFiring(cache.playerId, true)
end,
})
local pump = lib.zones.sphere({ coords = vec3(265.0, -1261.0, 29.3), radius = 6.0, onEnter = function() lib.showTextUI('[E] Refuel') end, onExit = function() lib.hideTextUI() end })
-- later: safe:remove()onEnter and onExit fire once; inside runs every frame while the player is in the zone, which is what DisablePlayerFiring needs. Set debug = true to see the shape while developing.
Drawing zones in game
- Give yourself the ACE:
add_ace group.admin command.zone allow. - Type
/zone poly(orbox,sphere) and follow the on-screen controls to place points. - Name and save the zone; ox_lib appends ready-to-paste code to
ox_lib/created_zones.lua.
PolyZone (older resources)
local zone = BoxZone:Create(vector3(441.0, -982.0, 30.7), 10.0, 8.0, {
name = 'mrpd_lobby',
heading = 0,
minZ = 29.0,
maxZ = 33.0,
debugPoly = false,
})
zone:onPlayerInOut(function(isInside)
print(isInside and 'entered' or 'left')
end)PolyZone (with BoxZone, CircleZone, PolyZone:Create and ComboZone) is still a dependency of many QBCore resources, but it is no longer actively developed. New code should use ox_lib zones; there is no need to rewrite working resources just to switch.
Zones, points or targets?
| Need | Use |
|---|---|
| React when entering an area | Zone |
| Show “[E] Open” near one spot | lib.points or a small sphere zone |
| Click on a specific object, NPC or door | ox_target — see ox_target guide |
Server-side confirmation
Zones live on the client. When entering a zone unlocks something valuable — selling drugs, a job payout — check the player’s coordinates on the server too: #(GetEntityCoords(GetPlayerPed(src)) - zoneCenter) < radius. See secure server events.
Frequently asked questions
How do I create a zone in FiveM?
With ox_lib: lib.zones.box, lib.zones.sphere or lib.zones.poly with onEnter/onExit handlers.
Is PolyZone still used?
Yes, by many older and QBCore resources, but it is no longer actively developed. ox_lib zones are the modern replacement.
How do I draw a polygon zone in game?
Use ox_lib’s restricted /zone poly command; saved zones are written to created_zones.lua in ox_lib.
Do zones cost performance?
Very little, as long as inside handlers stay light.
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
- FrameworksGetting started with ox_libStart ox_lib before your resource, add shared_script '@ox_lib/init.lua' and lua54 'yes' to your fxmanifest, and the global lib becomes available. Use cache.ped/cache.vehicle instead of calling natives in loops, lib.callback for client↔server requests, lib.notify, lib.progressBar, lib.registerContext/lib.showContext, lib.inputDialog, lib.points and lib.zones for interaction, and lib.addCommand for commands with ACE restrictions.
- FrameworksAdding interactions with ox_targetCall ox_target exports from your client script: addModel for every prop of a model, addGlobalVehicle/addGlobalPed/addGlobalPlayer for all of a type, addLocalEntity/addEntity for specific entities, and addBoxZone/addSphereZone for places. Each option has a name, label, icon, optional distance (default 7), groups, items and canInteract, and runs onSelect, an event, a serverEvent or a command.
- EngineeringWriting server events that cannot be abusedAny client can call any event you registered with RegisterNetEvent, with any arguments. In each handler: copy source into a local, check argument types and ranges, re-derive everything from server state (prices, amounts, rewards), verify the player can do this now (distance, job, item, cooldown), and log refusals. Events only other server scripts should use are registered with AddEventHandler alone, so clients cannot trigger them.
- Engineeringresmon: finding the resource that is eating your framesPress F8 and type resmon 1 (or resmon true) to open the client resource monitor. The CPU msec column is how many milliseconds per frame each resource uses; idle resources should sit near 0.00–0.02 ms, and anything consistently above about 0.5 ms deserves a look. Sort by CPU, reproduce the situation where it lags, and inspect the worst resource’s loops.