Almost every server has at least one job written in-house. Knowing how to build a clean one is one of the highest-leverage skills a server developer can have.
The smallest viable job resource
Create a folder [jobs]/myjob. Inside, you need three files: fxmanifest.lua, client.lua, server.lua. The manifest declares your scripts, the client handles markers / target zones / UI, the server handles money, inventory, and validation.
The mental model
A job is just a state machine. Player starts a duty, hits a series of checkpoints, completes the cycle, gets paid. Everything else — animations, vehicles, props — is decoration.
Don't trust the client
Every payment must happen on the server, period. The client tells the server I finished step 3 but the server checks if the player is actually at the right coordinates and within a reasonable time window. This single rule prevents 95% of money-farm exploits.
Persistence
Use the framework's player object methods. xPlayer.addMoney() for ESX. Player.Functions.AddMoney() for QBCore. Don't write directly to the database from a job script — let the framework handle that.
Polish details that players notice
- Add a target zone (ox_target) for starting/stopping duty rather than a marker.
- Use simple notifications (ox_lib.notify) instead of broadcast chat.
- Add a job-specific outfit on duty start, save and restore the original on duty end.
- Pay slightly more for completed cycles than partial ones, to discourage griefing.
Wrapping up
A good job is 200 lines of clean code, not 2,000 lines of spaghetti. If your script is getting bigger than a coffee shop menu, you have probably mixed UI, payment, and state management — split them into separate files and you will wonder why you didn't sooner.
Written by
Alex Johnson
Server-owner-friendly tutorials, every week. Browse the marketplace for premium FiveM resources or reach out if you need a custom build.
