START HERE·MAKING THINGS HAPPEN·Verified June 2026 · Lua 5.4 · ox_lib 3.x
Learning with an AI assistant?
Copies this whole lesson - every step, code block, and the exact console errors - plus 2026 ground rules (no lua54 'yes', Cfx.re Portal, correct callback signatures) as a ready-to-paste mentor prompt.
Start Here · Making things happen

Commands: trigger code on demand

A command is the simplest way to make your code run on purpose. You type one word, press Enter, and a block of code you wrote fires. In this lesson you wire a word like hello to a function so that typing it does something real. By the end you will know exactly what every piece of RegisterCommand does and why one little true decides who is allowed to run your code.

You'll learn
What a command is, how RegisterCommand wires a typed word to a handler, and how to read who ran it and what they typed.
Time
~10 minutes
Difficulty
Beginner
You need
The qu_hello resource from the events lesson, a text editor, and a local FiveM setup you can restart.
BEFORE YOU START

What a command is

A command is a word you type to make code run. When you type a word and press Enter in the console or in chat, FiveM looks for code that was attached to that word and runs it. That is the whole idea. The word is a doorbell, and your code is what happens when the bell rings.

You attach code to a word with a FiveM native called RegisterCommand. A native is a function the FiveM platform hands you for free, ready to use. RegisterCommand is the one that says, "when someone types this word, run this code." The block of code it runs is called the handler: the function you write and hand to FiveM to keep and run later.

Vocabulary

command
A word you type and press Enter to make code run. Example: hello.
RegisterCommand
The FiveM native that connects a command word to a handler function.
handler
The function you write to run when the command fires. Also called a callback.
source
A number FiveM passes to the handler telling you who ran the command. The server console is 0; a player is their server id.
args
A table FiveM passes to the handler holding the extra words the person typed after the command, in order.
restricted flag
The last value you pass to RegisterCommand. true locks the command behind admin permissions; false lets any player run it from chat.

Why commands matter

While you are building a feature, you almost never want to wait for the real game moment that triggers it. Picture a feature that fires when a player enters a garage. To test it, you would have to load in, walk to the garage, and stand in the right spot every single time. That is slow, and you will do it a hundred times.

A command skips all of that. You write a word, type it, and the code runs immediately. It is the fastest way to poke your own code by hand and see if it works. Coders lean on this constantly, long after they stop being beginners.

Commands are also how real admin tools are built. Every /heal, /givecar, and /setjob you have seen on a server is a command underneath. An admin types the word, the handler runs, and the game state changes. Learn the small version now and you have learned the skeleton of all of them.

The pattern never changes, no matter how big the feature gets. A typed word arrives, FiveM finds the matching handler, and your code runs. A one-line debug command and a full admin menu are the same machine at different sizes.

The shape of RegisterCommand

Here is the full shape. Read it once, then we will take every argument apart.

lua
RegisterCommand('name', function(source, args, rawCommand)
    -- your code goes here
end, true)

RegisterCommand takes three arguments, separated by commas: the command name, the handler function, and the restricted flag. The two dashes -- start a comment, a note for humans that Lua ignores when it runs.

The name

lua
'name'

The first argument is the command name, written as a string (text wrapped in quotes). This is the exact word a person types to fire the command. If you register 'hello', then typing hello runs it. The name does not have to match your resource name or your file name. It is just the word you pick.

The handler and its source and args

lua
function(source, args, rawCommand)
    -- your code goes here
end

The second argument is the handler: the function that runs when the command fires. Everything between function(...) and end is the body. Lua marks the end of a function with the word end, not curly braces like some other languages.

When the command fires, FiveM passes three values into your handler so your code knows the details of what just happened:

  • source tells you who ran it. It is a number. When the command comes from the server console, source is 0. When a player runs it, source is that player's server id, a number that identifies them while they are connected.
  • args is a table (Lua's word for an ordered list) of the extra words the person typed after the command. If someone types hello there world, then args[1] is 'there' and args[2] is 'world'. You read items by their position, starting at 1.
  • rawCommand is the entire line of text exactly as it was typed, command word included. You will rarely need it as a beginner, but FiveM hands it to you anyway.

You only have to name the values you actually use. If your handler ignores args and rawCommand, you can write function(source) or even function() and leave them out. FiveM still passes them; you just choose not to catch them.

The restricted flag, true vs false

lua
true

The third argument is the restricted flag, and it decides who is allowed to run the command.

  • true means the command is restricted. Only the server console and admins you have granted permission can run it. A normal player typing it in chat gets nothing.
  • false means the command is open. Any connected player can run it straight from their chat box.

This one value is a real security decision, not a detail. We cover it fully two sections down.

Build one

Open the qu_hello resource from the events lesson. You are going to add a /hello command that prints who ran it, then restart and run it from the console.

Open the resource code

You are looking at the server script for qu_hello.

Open the server script inside your qu_hello resource (the file your fxmanifest.lua lists as a server_script). You will add the command at the bottom, below whatever is already there.

Add the hello command

The file now registers a restricted hello command.

Paste this at the end of the file:

lua
RegisterCommand('hello', function(source, args, rawCommand)
    print('[qu_hello] hello was run by source ' .. source)
end, true)

The .. joins two strings end to end, so the message and the source number print as one line. The true at the end keeps the command restricted to the console and admins.

Restart the resource

The server has loaded your new command.

Open the txAdmin Live Console (the text box at the bottom of the txAdmin web panel where you type server commands) and run:

text
restart qu_hello

Run the command

Your handler fires and prints to the console.

Still in the txAdmin Live Console, type the command word and press Enter:

text
hello

The source is 0 because you ran it from the server console, and the console is always source zero.

The restricted flag and safety

Go back to that last argument, the true, and take it seriously. The restricted flag is the difference between a tool only you can use and a tool everyone on your server can use.

  • true means restricted. Only the server console and players you have given an ACE permission can run the command. ACE is FiveM's permission system, the list that says which players are allowed to do admin things. A normal player gets silence when they try.
  • false means open. Every connected player can fire the command from chat, no permission needed.

The rule to lock in: anything that changes game state must stay restricted. A command that heals a player, gives money, spawns a car, or sets a job has real power. If you leave one of those at false, every player on your server can heal themselves, print money, and spawn whatever they like. Open, state-changing commands are one of the most common ways FiveM servers get wrecked.

Common beginner mistakes

SymptomFix
The command does nothing when a player runs it in chatThe restricted flag is true, so only the server console and ACE-permitted admins can run it. That is correct and safe. Test it from the txAdmin Live Console, not the in-game chat box, or grant the player an ACE permission on purpose.
attempt to concatenate a nil value (field '?')You read args[1] when no argument was typed, so it is nil and the .. join fails. Guard it with a fallback: args[1] or 'none' returns the word none when nothing was passed.
Nothing prints anywhere when you type the commandYou are typing a server command in the wrong place. print on a server script lands in the server console (the txAdmin Live Console), not the in-game F8 client console. Run the command from the server console and read the output there.
Why should a /givemoney command keep restricted set to true?

Because it changes game state, it hands out money. With true, only the server console and ACE-permitted admins can run it, which is who you want giving money. If you set it to false, every connected player could type /givemoney from chat and pay themselves whatever they want. Any command that changes the game or trusts player input must stay restricted so only people you have approved can fire it.

Try it yourself

What you can do now

  • Explain that a command is a typed word wired to a handler that runs when the word is entered.
  • Write RegisterCommand and say what each argument does: the name, the handler, and the restricted flag.
  • Read source to know who ran a command and args to read the words they typed after it.
  • Choose true to keep a state-changing command restricted, and explain why false is dangerous for those.
  • Guard a missing argument with args[1] or 'fallback' so your handler never breaks on nil.

You can now make your own code run on demand and read who triggered it. Next up is "Callbacks: ask the server and wait for an answer," where the client asks the server a question and waits for the real number before it continues, instead of just firing a message off and moving on.