FiveM Docs
Getting Started

Lua Annotations for ESX

Use LuaLS annotations in ESX scripts - document functions, classes and types, reuse the xPlayer and ESXJob types from es_extended, and set up VS Code for autocomplete.

Annotations are special comments that tell the Lua language server (LuaLS, the "Lua" extension by sumneko) what types your functions take and return. Your editor then shows autocomplete, parameter hints and warnings, for example when you pass a string where a number is expected or forget to check a value that can be nil. They cost nothing at runtime: FiveM treats them as ordinary comments.

ESX Legacy itself is annotated, so with the right setup you get full autocomplete for xPlayer, accounts, jobs and items in your own scripts.

Editor setup

  1. Install Lua by sumneko and CfxLua IntelliSense.
  2. Point the language server at your copy of es_extended so it reads the ESX types:
.vscode/settings.json
{
  "Lua.runtime.version": "Lua 5.4",
  "Lua.workspace.library": [
    "C:/FXServer/esx-server/resources/[core]/es_extended"
  ],
  "Lua.diagnostics.globals": ["ESX", "Config"]
}

Use the real path to your server's es_extended folder. On Linux or macOS use a normal Unix path.

Annotation basics

An annotation is a comment line that starts with --- followed by a tag such as @param. It applies to the code directly below it.

TagPurposeExample
@paramType of a function parameter. Add ? for optional.---@param amount number
@returnType of a return value, optionally with a name.---@return boolean success
@classDeclares a table type. Can extend another class.---@class ShopItem
@fieldA field of a class.---@field price number
@typeType of a variable.---@type xPlayer?
@aliasA name for a type or a set of literal values.---@alias Account 'money'|'bank'
@castTell the server a variable has a narrower type from here on.---@cast xPlayer xPlayer
@deprecatedMarks a function as deprecated; callers get a strikethrough.---@deprecated
@diagnosticDisable a warning for a line or file.---@diagnostic disable-next-line: undefined-global

Common types: string, number, integer, boolean, table, function, nil, any, arrays like string[], maps like table<string, number>, unions like string|number, and FiveM's vector3.

Documenting a function

server/utils.lua
--- Pays a player from a society account.
--- Returns false when the player is not loaded or the amount is invalid.
---@param playerId number Server ID of the player
---@param amount integer Amount in dollars, must be positive
---@param reason? string Shown in logs, defaults to "Payment"
---@return boolean success
local function payPlayer(playerId, amount, reason)
    if amount <= 0 then return false end

    local xPlayer = ESX.GetPlayerFromId(playerId)
    if not xPlayer then return false end

    xPlayer.addAccountMoney('bank', amount, reason or 'Payment')
    return true
end

Now hovering payPlayer shows the description, and calling payPlayer('1', 500) gets a warning because '1' is a string.

Using the ESX types

es_extended defines these classes in server/classes/player.lua:

ClassDescribes
xPlayerThe full server-side player object (extends StaticPlayer)
StaticPlayerThe method interface of a player
ESXAccountAn account: name, money, label, round, index
ESXJobA job: name, label, grade, grade_name, grade_label, grade_salary, onDuty, ...
ESXItem, ESXInventoryItemAn item and an item with count
ESXInventoryWeaponA weapon in the loadout with ammo, components, tintIndex

Use them in your own annotations:

server/main.lua
---@param xPlayer xPlayer
---@return boolean
local function isOnDutyPolice(xPlayer)
    local job = xPlayer.job ---@type ESXJob
    return job.name == 'police' and job.onDuty == true
end

RegisterNetEvent('my_police:action', function()
    local xPlayer = ESX.GetPlayerFromId(source) ---@type xPlayer?
    if not xPlayer then return end

    if isOnDutyPolice(xPlayer) then
        -- autocomplete works here: xPlayer.getAccount, xPlayer.showNotification, ...
    end
end)

Marking the variable as xPlayer? (nullable) makes the language server warn you if you use it before the nil check, which is exactly the bug that causes most attempt to index a nil value errors.

Declaring your own classes

Describe the shape of your config or data tables once and get checks everywhere you use them.

config.lua
---@class ShopItem
---@field name string Item name from the items table
---@field label string
---@field price integer

---@class ShopConfig
---@field coords vector3
---@field items ShopItem[]

---@type ShopConfig
Config = {
    coords = vector3(25.7, -1347.3, 29.5),
    items = {
        { name = 'water', label = 'Water', price = 25 },
        { name = 'bread', label = 'Bread', price = 15 },
    },
}

A typo like prcie = 15 now shows a warning instead of a silent nil at runtime.

Aliases for fixed values

---@alias NotifyType 'info'|'success'|'error'

---@param message string
---@param notifyType? NotifyType
local function notify(message, notifyType)
    ESX.ShowNotification(message, notifyType or 'info')
end

The editor now suggests only the three valid notification types.

Tips

  • Annotate public functions and config tables first. That is where most type mistakes happen.
  • Keep descriptions short. One line about what and anything surprising about when it returns nil.
  • Do not disable diagnostics for a whole workspace to silence one warning. Use ---@diagnostic disable-next-line where needed.
  • The full annotation reference is in the LuaLS wiki.

Frequently asked questions

Independent documentation

esx-fivem.com is a community project and is not affiliated with the ESX Framework team. Facts on this page were checked against the upstream source. Official resources: docs.esx-framework.org and github.com/esx-framework.
Edit on GitHub

Last updated on

On this page