FiveM Lua Scripting: Getting Started with Custom Scripts in 2026

Published on

Want to create custom FiveM jobs, systems, or features? This beginner's guide to Lua scripting in FiveM will get you writing your first resource.

FiveM server Every custom job, unique mechanic, and special feature on a FiveM server is a "resource" written in Lua. If you can write Lua, you can build anything. Here is how to start.

The Resource Structure

Every FiveM resource is a folder containing:

my_resource/
  fxmanifest.lua    # Tells FiveM what files are in this resource
  client.lua        # Code running on each player's client
  server.lua        # Code running on your server
  shared.lua        # Code running on both sides

fxmanifest.lua (required):

fx_version 'cerulean'
game 'gta5'

author 'YourName'
description 'My Custom Resource'
version '1.0.0'

shared_script 'shared.lua'
client_script 'client.lua'
server_script 'server.lua'

Client/Server Architecture

Understanding which code runs where is fundamental:

Client-side (client.lua): Access to GTA V native functions (player position, drawing UI, vehicle control). Runs on each connected player's PC.

Server-side (server.lua): Access to server state, database, player management. Runs once on your server machine.

Communication: Client and server communicate through events:

-- Client sends event to server:
TriggerServerEvent('myResource:doSomething', someData)

-- Server handles it:
RegisterNetEvent('myResource:doSomething')
AddEventHandler('myResource:doSomething', function(someData)
    local src = source  -- The player who fired the event
    print('Player ' .. src .. ' sent: ' .. someData)
    -- Do server-side logic here
end)

-- Server sends event back to client:
TriggerClientEvent('myResource:response', src, 'done')

Your First Job System (Minimal Example)

-- server.lua
local jobPlayers = {}

RegisterNetEvent('myjob:clockIn')
AddEventHandler('myjob:clockIn', function()
    local src = source
    jobPlayers[src] = GetGameTimer()
    TriggerClientEvent('myjob:started', src)
    print('Player ' .. src .. ' clocked in')
end)

RegisterNetEvent('myjob:clockOut')
AddEventHandler('myjob:clockOut', function()
    local src = source
    if jobPlayers[src] then
        local timeWorked = (GetGameTimer() - jobPlayers[src]) / 1000 / 60 -- minutes
        local pay = math.floor(timeWorked * 15) -- €15 per minute
        -- Add pay logic here (QBCore money function etc.)
        jobPlayers[src] = nil
        TriggerClientEvent('myjob:ended', src, pay)
    end
end)

Learning Resources

Start by reading and modifying existing open-source resources before writing from scratch. The community's qb-smallresources repository contains dozens of small examples perfect for learning.

Host your custom FiveM scripts on Space-Node

Launch Your FiveM Server Today

Get started with professional GTA V roleplay hosting powered by enterprise hardware. Instant deployment and 12/7 support included.