Offre Durée limitée : -10% sur tout le site* avec le code WELCOME10

Créer son premier script FiveM en Lua : tutoriel débutant

Mis à jour le 23 octobre 2026 15 min de lecture 14 sections

Administrer un serveur FiveM, c'est d'abord assembler des scripts existants : framework, garage, inventaire, métiers. Mais dès qu'une mécanique personnalisée manque, ou qu'un script tiers pose plus de problèmes qu'il n'en résout, savoir écrire son propre code Lua devient un avantage concret. Ce guide couvre la création d'un premier script fonctionnel, de la structure des fichiers au déploiement sur le serveur, en s'appuyant sur la documentation officielle Cfx.re.

Lua est le langage de script le plus utilisé dans l'écosystème FiveM. FiveM embarque CfxLua, une version modifiée de Lua 5.4, avec des ajouts spécifiques : vecteurs natifs (vector3, vector4), hachage de chaînes à la compilation, et une boucle d'exécution intégrée via Citizen.CreateThread. C'est le même langage que celui utilisé par ESX Legacy, QBCore et la grande majorité des ressources communautaires. FiveM supporte aussi JavaScript et C#, mais Lua reste le choix par défaut pour la plupart des développeurs de ressources.

Prérequis

  • Un serveur FiveM fonctionnel avec un accès au système de fichiers (VPS avec accès root ou panel type txAdmin/Pterodactyl). Si votre serveur tourne chez un hébergeur FiveM, vérifiez que vous disposez d'un accès FTP ou d'un gestionnaire de fichiers dans le panel ;
  • Un éditeur de code : Visual Studio Code avec l'extension cfxlua-vscode (IntelliSense pour les fonctions natives FiveM et les types Lua) ;
  • Une connaissance de base de Lua (variables, fonctions, tables, boucles). La syntaxe Lua est plus légère que celle de Python ou de JavaScript : pas de point-virgule obligatoire, pas de typage explicite ;
  • Le fichier de configuration server.cfg du serveur, accessible en écriture.

Si votre serveur n'est pas encore en place, notre guide de mise en place d'un serveur FiveM couvre l'installation complète avant de commencer à scripter.

Préparer l'environnement de développement

Avant d'écrire la première ligne de code, configurez votre poste de travail pour travailler efficacement. L'éditeur de code et les extensions adaptées évitent la majorité des erreurs de syntaxe et accélèrent l'écriture des scripts.

Visual Studio Code et extensions

Installez Visual Studio Code (disponible sous Windows, macOS et Linux), puis ajoutez ces extensions depuis le marketplace :

  • cfxlua-vscode (ou FiveM Lua IntelliSense) : autocomplétion des fonctions natives FiveM, des événements et des types CfxLua. L'extension charge la liste complète des natives depuis la documentation Cfx.re et propose les paramètres attendus ;
  • Lua (sumneko) : diagnostic de syntaxe, navigation dans le code, détection des variables inutilisées. Ce plugin analyse le code en temps réel et signale les erreurs avant l'exécution ;
  • FiveM Natives (optionnel) : documentation des natives directement dans l'éditeur au survol de la fonction.

Connexion au serveur distant

Si votre serveur FiveM tourne sur un VPS distant, vous avez plusieurs méthodes pour transférer les fichiers de vos scripts :

  • FTP/SFTP : connectez-vous avec un client comme FileZilla en utilisant l'adresse IP du serveur, le port et les identifiants d'authentification. SFTP chiffre la connexion via le protocole SSH ;
  • Terminal SSH : en ligne de commande, connectez-vous au serveur avec ssh utilisateur@adresse-ip et éditez les fichiers directement dans le shell avec nano ou vim ;
  • Panel txAdmin ou Pterodactyl : le gestionnaire de fichiers intégré au panel permet de créer des dossiers, d'éditer des fichiers et de téléverser des scripts sans quitter le navigateur.

Pour un flux de travail fluide, développez en local dans Visual Studio Code, testez la syntaxe, puis transférez le dossier de la ressource sur le serveur. Sauvegardez vos scripts dans un dépôt Git pour garder un historique des modifications et pouvoir revenir en arrière après une mise à jour qui casse quelque chose.

Structure d'une ressource FiveM

Dans FiveM, chaque script est une ressource : un dossier dans le répertoire resources/ du serveur, contenant au minimum un fichier manifeste et un ou plusieurs fichiers Lua. La structure minimale d'une ressource :

resources/
  [mon-script]/
    fxmanifest.lua       -- manifeste : declare les fichiers et les metadonnees
    client.lua           -- code execute cote client (chaque joueur)
    server.lua           -- code execute cote serveur (une seule instance)

Le fichier fxmanifest.lua est obligatoire. C'est lui que FiveM lit au démarrage pour savoir quels fichiers charger et dans quel contexte (client ou serveur). Sans ce fichier, le dossier est ignoré. Les ressources sont organisées en sous-dossiers dans resources/ : par convention, [local] pour vos scripts personnalisés, [esx] ou [qb] pour les scripts du framework.

Le fichier fxmanifest.lua

Le manifeste déclare la version de l'API, le jeu cible et les fichiers à charger. Voici un manifeste minimal pour une ressource avec un script côté client et un script côté serveur :

fx_version 'cerulean'
game 'gta5'

author 'VotreNom'
description 'Mon premier script FiveM'
version '1.0.0'

client_script 'client.lua'
server_script 'server.lua'

Les champs obligatoires sont fx_version et game. La valeur 'cerulean' est la version d'API la plus récente et donne accès à toutes les fonctionnalités actuelles. Pour un serveur RedM, remplacez 'gta5' par 'rdr3'. Les champs author, description et version sont des métadonnées utiles pour l'organisation, mais pas techniquement bloquants.

Pour les ressources plus complexes, le manifeste accepte des directives supplémentaires :

DirectiveRôleExemple
shared_scriptFichier Lua chargé côté client et côté serveurshared_script 'config.lua'
client_scriptsListe de fichiers client (accolades pour plusieurs)client_scripts { 'client/*.lua' }
server_scriptsListe de fichiers serveurserver_scripts { 'server/*.lua' }
filesFichiers embarqués accessibles par le client (JSON, HTML)files { 'ui/index.html' }
ui_pagePage NUI (interface HTML intégrée au jeu)ui_page 'ui/index.html'
dependencyRessource requise, chargée avant celle-cidependency 'oxmysql'

Écrire un script côté client

Le code côté client s'exécute sur la machine de chaque joueur connecté. C'est là qu'on interagit avec le monde du jeu : position du personnage, véhicules, interface, effets visuels. Chaque joueur a sa propre instance du script client, sans variables partagées entre les connexions.

Un premier exemple concret : une commande /position qui affiche les coordonnées du joueur dans le chat.

-- client.lua

RegisterCommand('position', function()
    local ped = PlayerPedId()
    local coords = GetEntityCoords(ped)

    TriggerEvent('chat:addMessage', {
        args = {
            string.format('Position : %.2f, %.2f, %.2f', coords.x, coords.y, coords.z)
        }
    })
end, false)

Trois éléments clés dans cet exemple :

  • RegisterCommand enregistre une commande utilisable dans le chat avec le préfixe /. Le troisième argument (false) indique que la commande n'est pas restreinte aux administrateurs ;
  • PlayerPedId() et GetEntityCoords() sont des fonctions natives de FiveM, c'est-à-dire des fonctions prédéfinies qui interagissent directement avec le moteur du jeu GTA V ;
  • TriggerEvent déclenche un événement local (ici chat:addMessage pour afficher un message dans le chat du joueur).

Écrire un script côté serveur

Le code côté serveur s'exécute sur le serveur FiveM, en une seule instance. C'est le bon endroit pour la logique partagée entre joueurs : vérifications de droits, requêtes vers la base de données, distribution de récompenses, logs d'administration. Le serveur centralise la logique métier pour garantir l'intégrité des données : un joueur ne peut pas contourner une vérification qui s'exécute côté serveur.

Voici un script serveur qui enregistre une commande /annonce réservée aux administrateurs, qui envoie un message à tous les joueurs connectés :

-- server.lua

RegisterCommand('annonce', function(source, args)
    if not IsPlayerAceAllowed(source, 'command.annonce') then
        return
    end

    local message = table.concat(args, ' ')
    if message == '' then
        return
    end

    TriggerClientEvent('chat:addMessage', -1, {
        args = { '[Annonce] ' .. message }
    })

    print('[Annonce] ' .. GetPlayerName(source) .. ' : ' .. message)
end, true)

Les différences avec le script client :

  • Le premier argument de la fonction (source) est l'identifiant réseau du joueur qui a exécuté la commande ;
  • IsPlayerAceAllowed vérifie que le joueur a la permission command.annonce dans le système ACE (Access Control Entry) du serveur. Ce système d'authentification des permissions se configure dans server.cfg ;
  • TriggerClientEvent envoie un événement à un ou plusieurs clients. La valeur -1 cible toutes les connexions actives ;
  • print() écrit un log dans la console serveur. Le message apparaît dans le terminal du serveur et dans la console txAdmin.

Communication client-serveur avec les événements

Dans FiveM, le client et le serveur sont séparés. Pour qu'ils communiquent, on utilise des événements réseau. Le principe :

  • Le client déclenche un événement vers le serveur avec TriggerServerEvent('nomEvenement', ...) ;
  • Le serveur écoute cet événement avec RegisterNetEvent('nomEvenement') puis AddEventHandler ;
  • Le serveur peut répondre au client avec TriggerClientEvent('nomEvenement', source, ...).

Exemple complet : le joueur tape /solde, le client envoie une requête au serveur, le serveur renvoie un solde fictif.

-- client.lua

RegisterNetEvent('monscript:recevoirSolde')
AddEventHandler('monscript:recevoirSolde', function(montant)
    TriggerEvent('chat:addMessage', {
        args = { 'Votre solde : ' .. tostring(montant) .. ' $' }
    })
end)

RegisterCommand('solde', function()
    TriggerServerEvent('monscript:demanderSolde')
end, false)
-- server.lua

RegisterNetEvent('monscript:demanderSolde')
AddEventHandler('monscript:demanderSolde', function()
    local source = source
    -- En production, ce montant viendrait d'une requete vers la base de donnees
    local solde = 15000
    TriggerClientEvent('monscript:recevoirSolde', source, solde)
end)

Le préfixe monscript: dans le nom des événements est une convention qui évite les collisions avec d'autres ressources. RegisterNetEvent est obligatoire côté récepteur pour les événements réseau : sans lui, l'événement est ignoré silencieusement. Cette architecture client-serveur est fondamentale dans FiveM : le client ne doit jamais exécuter de logique critique (argent, inventaire, sanctions) directement.

Les fonctions natives

Les fonctions natives sont le point d'accès au moteur de jeu GTA V. FiveM en documente plusieurs milliers, organisées par catégorie (véhicules, peds, interface, météo, armes, etc.) dans la référence officielle sur docs.fivem.net/natives/. Quelques natives fréquemment utilisées côté client :

NativeRôleExemple
PlayerPedId()Récupère l'entité du personnage du joueurlocal ped = PlayerPedId()
GetEntityCoords(entity)Coordonnées d'une entité (vector3)local pos = GetEntityCoords(ped)
RequestModel(hash)Charge un modèle en mémoire (RAM)RequestModel(`adder`)
HasModelLoaded(hash)Vérifie si le modèle est chargéwhile not HasModelLoaded(`adder`) do Wait(100) end
CreateVehicle(...)Crée un véhicule dans le mondeCreateVehicle(hash, x, y, z, heading, true, false)
SetEntityAsNoLongerNeeded(entity)Libère l'entité de la mémoire du scriptSetEntityAsNoLongerNeeded(vehicle)
GetPlayerIdentifiers(source)Identifiants du joueur (serveur)GetPlayerIdentifiers(source)
GetNumPlayerIndices()Nombre de connexions actives (serveur)local count = GetNumPlayerIndices()

Pour trouver la bonne native, consultez la documentation officielle ou utilisez la barre de recherche sur docs.fivem.net. Chaque native indique si elle est client, serveur ou partagée, et documente les paramètres attendus. L'extension VS Code charge ces informations pour proposer l'autocomplétion directement dans l'éditeur.

Boucles et threads avec Citizen.CreateThread

Certaines logiques nécessitent une exécution continue : affichage d'un texte à l'écran, détection d'une zone, vérification d'une condition à chaque image (frame). FiveM fournit Citizen.CreateThread pour créer un thread coopératif, et Citizen.Wait (ou son alias Wait) pour contrôler la fréquence d'exécution.

-- client.lua : afficher un message a l'ecran en continu

Citizen.CreateThread(function()
    while true do
        Citizen.Wait(0)  -- 0 = chaque frame (~16 ms a 60 FPS)
        DrawTextOnScreen('Mon serveur FiveM', 0.5, 0.02)
    end
end)

function DrawTextOnScreen(text, x, y)
    SetTextFont(0)
    SetTextScale(0.5, 0.5)
    SetTextCentre(true)
    BeginTextCommandDisplayText('STRING')
    AddTextComponentSubstringPlayerName(text)
    EndTextCommandDisplayText(x, y)
end

Citizen.Wait(0) cède le contrôle au moteur de jeu à chaque frame. Sans cet appel, la boucle bloque le thread principal et le jeu se fige. Citizen.Wait(1000) attend une seconde, ce qui convient pour des vérifications moins fréquentes (détection de zone, mise à jour d'un compteur). Adaptez la valeur à la fréquence réellement nécessaire pour limiter la charge sur le processeur du client et la RAM du serveur.

Les exports : partager des fonctions entre ressources

Quand votre serveur compte plusieurs dizaines de ressources, certaines fonctions doivent être appelées depuis d'autres scripts. Les exports permettent à une ressource d'exposer des fonctions que les autres ressources peuvent exécuter sans passer par un événement réseau.

Déclarez un export dans votre script Lua :

-- server.lua de la ressource "monscript"

exports('GetPlayerMoney', function(playerId)
    -- En production, requete vers la base de donnees
    return 15000
end)

Appelez cet export depuis une autre ressource :

-- server.lua d'une autre ressource

local solde = exports.monscript:GetPlayerMoney(source)
print('Solde du joueur : ' .. tostring(solde))

Les exports sont synchrones : l'appel bloque jusqu'au retour de la fonction. C'est la méthode recommandée pour les appels entre ressources sur le même côté (serveur-serveur ou client-client), plus simple et plus performante que les événements. Pour les exports côté serveur, ajoutez server_export 'GetPlayerMoney' dans le manifeste, ou utilisez la syntaxe exports() directement dans le script Lua (les deux fonctionnent).

Déployer la ressource sur le serveur

Une fois les fichiers créés, le déploiement se fait en deux étapes :

  1. Copiez le dossier de votre ressource dans resources/[local]/ (ou tout autre sous-dossier de resources/ selon les configurations de votre serveur) ;
  2. Ajoutez la ligne suivante dans votre fichier de configuration server.cfg pour que la ressource se charge au démarrage :
ensure mon-script

Pour charger la ressource sans redémarrer le serveur, utilisez la console txAdmin ou le terminal de la console serveur :

refresh
start mon-script

refresh relit les manifestes de toutes les ressources. start charge et démarre la ressource ciblée. Pour exécuter un rechargement après modification du code :

restart mon-script

Surveillez les logs dans la console serveur après chaque start ou restart : les erreurs Lua s'affichent directement avec le nom du fichier et le numéro de ligne. Si votre serveur tourne sur un hébergement FiveM ElypseCloud avec txAdmin préinstallé, la console web affiche les mêmes logs en temps réel et permet d'exécuter les commandes serveur depuis le navigateur.

Déboguer un script Lua FiveM

Le débogage sur FiveM repose sur la lecture attentive des logs et quelques techniques simples :

  • print() côté serveur écrit un log dans la console du terminal serveur et dans txAdmin. C'est l'outil de débogage le plus direct pour vérifier qu'un événement est bien reçu ou qu'une variable contient la bonne valeur ;
  • La touche F8 ouvre la console client dans le jeu, qui affiche les erreurs et les print() côté client ;
  • Les erreurs Lua indiquent le fichier, le numéro de ligne et le type d'erreur (nil value, attempt to index, attempt to call, etc.). Lisez le message d'erreur avant de chercher ailleurs ;
  • Pour les problèmes d'événements réseau, ajoutez un print() dans le handler côté récepteur : si rien ne s'affiche dans les logs, l'événement n'arrive pas (vérifiez RegisterNetEvent, le nom exact de l'événement, et que la ressource est bien démarrée des deux côtés).

Erreurs courantes et leur cause :

Message d'erreur dans les logsCause probableSolution
attempt to call a nil valueFonction native mal orthographiée ou appelée dans le mauvais contexte (client/serveur)Vérifiez le nom exact dans la documentation des natives
attempt to index a nil valueVariable non initialisée ou retour inattendu d'une fonctionAjoutez un print() avant la ligne pour inspecter la valeur
No such exportLa ressource exportant la fonction n'est pas démarréeVérifiez l'ordre de chargement avec dependency dans le manifeste
Aucune erreur, mais rien ne se passeÉvénement non enregistré, RegisterNetEvent manquantAjoutez un print() au début du handler pour confirmer la réception
SCRIPT ERROR: @monscript/...Erreur d'exécution dans le fichier indiquéLe numéro de ligne dans le log pointe vers la source du problème

Pour aller plus loin dans le diagnostic de problèmes serveur, notre guide sur l'optimisation des performances d'un serveur FiveM couvre les outils de monitoring intégrés à txAdmin (utilisation du processeur, RAM, temps d'exécution des ressources) et les indicateurs à surveiller. Si vos scripts exécutent des requêtes vers une base de données MySQL, notre guide de liaison MySQL sur serveur FiveM détaille la configuration et les bonnes pratiques pour les requêtes asynchrones.

Bonnes pratiques pour vos scripts

  • Préfixer les événements réseau avec le nom de la ressource (monscript:nomEvenement) pour éviter les collisions avec d'autres scripts ou frameworks ;
  • Ne jamais faire confiance au client : toute donnée envoyée par TriggerServerEvent peut être falsifiée par un tricheur. Vérifiez côté serveur avant d'exécuter une action (argent, objets, téléportation). L'authentification des permissions passe par le système ACE, configuré dans server.cfg ;
  • Libérer les ressources mémoire : après avoir créé un véhicule ou chargé un modèle, appelez SetEntityAsNoLongerNeeded et SetModelAsNoLongerNeeded pour éviter les fuites de RAM. Un serveur avec beaucoup de scripts qui ne libèrent pas leurs entités consomme de plus en plus de mémoire jusqu'au crash ;
  • Adapter la fréquence des boucles : Wait(0) (chaque frame) uniquement pour l'affichage. Pour les vérifications logiques, Wait(500) ou Wait(1000) suffit et réduit la charge processeur ;
  • Versionner et sauvegarder le code : utilisez Git pour suivre les modifications. Avant chaque mise à jour majeure, faites une sauvegarde complète du dossier resources/ et de la base de données. Notre guide sur les sauvegardes de serveur FiveM détaille les stratégies de backup automatisé ;
  • Séparer la configuration du code : placez les valeurs modifiables (messages, coordonnées, montants) dans un fichier config.lua chargé via shared_script dans le manifeste. Les administrateurs du serveur peuvent ainsi ajuster les configurations sans toucher au code principal ;
  • Structurer les logs : utilisez print() avec des préfixes clairs ([monscript]) pour retrouver vos messages dans les logs du terminal. Sur un serveur avec des dizaines de ressources, des logs non identifiés sont inutiles.

Aller plus loin

Ce premier script couvre les bases : manifeste, commandes, natives, événements réseau, threads, exports. Pour approfondir :

  • Intégrer votre script avec un framework (ESX Legacy ou QBCore) pour accéder aux systèmes d'argent, d'inventaire et de métiers existants ;
  • Connecter votre script à une base de données MySQL pour persister les données entre les redémarrages du serveur. Les requêtes passent par une ressource dédiée comme oxmysql, qui gère le pool de connexions à la base de données ;
  • Lire et installer des scripts communautaires en sachant évaluer leur fiabilité ;
  • Configurer txAdmin pour gérer les ressources, les logs et les redémarrages depuis une interface web ;
  • Sécuriser votre serveur contre les tricheurs avec un anti-cheat adapté ;
  • Configurer un nom de domaine avec enregistrement SRV pour que les joueurs se connectent avec une adresse lisible plutôt qu'une adresse IP.

La documentation officielle Cfx.re (docs.fivem.net) reste la référence pour les natives, les événements et les fonctionnalités avancées comme les exports, le NUI (interface HTML/JavaScript intégrée au jeu) et le système de state bags pour synchroniser des données entre client et serveur.

FAQ

Quel langage de programmation utiliser pour scripter sur FiveM ?

FiveM supporte trois langages de script : Lua, JavaScript et C#. Lua est le plus utilisé dans l'écosystème FiveM, notamment par les frameworks ESX Legacy et QBCore. FiveM embarque CfxLua, une version modifiée de Lua 5.4, avec des fonctionnalités spécifiques comme les vecteurs natifs et le hachage de chaînes à la compilation.

Comment structurer une ressource FiveM ?

Une ressource FiveM est un dossier dans le répertoire resources/ du serveur. Elle contient au minimum un fichier fxmanifest.lua (le manifeste qui déclare les métadonnées et les fichiers à charger) et un ou plusieurs fichiers Lua. Le manifeste doit contenir au moins fx_version et game. Les scripts sont séparés en client_script (exécuté sur chaque joueur) et server_script (exécuté sur le serveur).

Que sont les fonctions natives dans FiveM ?

Les fonctions natives sont des fonctions prédéfinies qui permettent d'interagir avec le moteur de jeu GTA V depuis un script FiveM. Elles couvrent les véhicules, les personnages, l'interface, la météo, les armes et bien d'autres systèmes. Exemples courants : PlayerPedId() pour récupérer le personnage du joueur, GetEntityCoords() pour obtenir les coordonnées d'une entité, RegisterCommand() pour enregistrer une commande.

Comment faire communiquer un script client et un script serveur ?

La communication entre client et serveur passe par le système d'événements réseau de FiveM. Le client envoie un événement au serveur avec TriggerServerEvent(), le serveur l'écoute avec RegisterNetEvent() et AddEventHandler(). Le serveur peut répondre au client avec TriggerClientEvent(). RegisterNetEvent est obligatoire côté récepteur pour les événements réseau.

Comment déployer un script sur un serveur FiveM ?

Copiez le dossier de votre ressource dans le répertoire resources/ du serveur, puis ajoutez la ligne ensure nom-de-la-ressource dans le fichier server.cfg. Pour charger la ressource sans redémarrer, tapez refresh puis start nom-de-la-ressource dans la console serveur ou dans txAdmin. La commande restart permet de recharger une ressource après modification du code.

Pourquoi mon script Lua bloque le jeu avec une boucle while true ?

Une boucle while true dans un thread FiveM doit obligatoirement contenir un appel à Citizen.Wait() ou Wait(). Sans cet appel, la boucle ne rend jamais le contrôle au moteur de jeu et le client se fige. Utilisez Citizen.Wait(0) pour une exécution à chaque frame (affichage), ou Citizen.Wait(500) à Citizen.Wait(1000) pour des vérifications logiques moins fréquentes.

Comment déboguer un script FiveM qui ne fonctionne pas ?

Consultez les logs dans la console serveur (terminal ou txAdmin) et la console client (touche F8). Les erreurs Lua indiquent le fichier et le numéro de ligne. Ajoutez des print() dans vos handlers pour vérifier que les événements sont bien reçus et que les variables contiennent les valeurs attendues. Pour les événements réseau, vérifiez que RegisterNetEvent est présent côté récepteur.

Qu'est-ce qu'un export dans FiveM et quand l'utiliser ?

Un export est une fonction exposée par une ressource que d'autres ressources peuvent exécuter directement, sans passer par un événement réseau. Déclarez un export avec exports('NomFonction', function() ... end) dans votre script Lua. Appelez-le depuis une autre ressource avec exports.nomressource:NomFonction(). Les exports sont synchrones et recommandés pour les appels entre ressources sur le même côté (serveur-serveur ou client-client).

Quelles extensions Visual Studio Code installer pour scripter sur FiveM ?

Installez cfxlua-vscode (ou FiveM Lua IntelliSense) pour l'autocomplétion des fonctions natives et des types CfxLua, et l'extension Lua de sumneko pour le diagnostic de syntaxe et la navigation dans le code. Ces extensions détectent les erreurs avant l'exécution et proposent la documentation des natives directement dans l'éditeur.