Your first line of Lua
Every coder starts the same way: one line, one message, one visible result. In this lesson that result is a line you control, printed in your FiveM server console on demand. By the end you will understand a string, the print function, and how RegisterCommand turns a typed word into running code.
Build it
Make the resource folder
Inside your server's resources folder, create this folder:
resources/qu_first_line_of_luaCreate the files
Create this exact file layout:
resources/qu_first_line_of_lua/
fxmanifest.lua
server.luaWrite fxmanifest.lua
Open fxmanifest.lua and paste this:
fx_version 'cerulean'
game 'gta5'
server_script 'server.lua'Older tutorials add a lua54 'yes' line here. As of June 2025 that setting is deprecated and ignored: Lua 5.4 is now the only Lua runtime, so you leave it out.
Write the lesson code
Open server.lua and paste this:
RegisterCommand('first_line_of_lua', function()
print('[qu_first_line_of_lua] proof line')
end, true)Start and test it
Open server.cfg and add this line:
ensure qu_first_line_of_luaSave the file. Now open the txAdmin Live Console (the text box at the bottom of the txAdmin web panel where you type server commands) and type this, then press Enter:
restart qu_first_line_of_luaStill in that same txAdmin Live Console, type the command itself and press Enter:
first_line_of_luaHow it works
You ran it and the line appeared. Now take the code apart so the next time you write Lua you are deciding, not copying. There are really only two lines that matter, and one piece of punctuation that trips up everyone at the start.
The string you printed
Look at the text inside the parentheses on the print line:
'[qu_first_line_of_lua] proof line'That is a string: a run of text that Lua treats as a single value. The single quotes are not part of the text. They are fences that mark where the text starts and ends. Lua also accepts double quotes, so "proof line" means the same thing as 'proof line'. Pick one style and stay consistent. The [qu_first_line_of_lua] part at the front is just text you typed on purpose. It is a tag, so that when twenty resources are all printing at once, you can scan the console and find your own lines. That habit pays off the moment your server has more than one script running.
The print function
print('[qu_first_line_of_lua] proof line')print is a function: a named action you can call. You call it by writing its name, then a pair of parentheses, and inside the parentheses you put what you want it to act on. Here you hand it one string. The value you hand a function is called an argument. So in plain words this line says, take this string and write it to the console. That is the entire job of print. It does not pop up on a player's screen and it does not appear in chat. It writes to the server console. If you run your server through txAdmin, that output shows up in the txAdmin Live Console (it is also the same text you would see in the raw FXServer console window).
The mental model to lock in: print is your eyes inside running code. Code that is working silently tells you nothing. A well-placed print is how you ask the program what it is actually doing, instead of guessing. Every debugging session you will ever run starts with the same move, dropping a print somewhere to see whether the code even reached that point.
The command that runs it
RegisterCommand('first_line_of_lua', function()
print('[qu_first_line_of_lua] proof line')
end, true)This is the line that decides when your print runs. RegisterCommand is a FiveM native: a function the platform gives you for free. It wires a typed command to a block of code. Read it as three arguments separated by commas:
'first_line_of_lua'is the command name, a string. This is the word you type in the console to fire it. It does not have to match the resource name. It just happens to here.function() ... endis the code to run when the command fires. Everything betweenfunction()andendis the body. Right now the body is one print, but it could be a hundred lines. This is called the handler or callback: code you hand to FiveM and say, hold onto this and run it later, when the command is typed.trueis the restricted flag. Withtrue, the command requires an ace permission, which is why it runs cleanly from the server console. The server console has full rights. Set it tofalseand any connected player could run the command from their own chat box. For a server-side proof line you do not want players triggering,trueis the safe default. Security rule to carry forward: any command that changes game state or trusts player input (heal, give item, set money) must stay restricted (true) and gated behind an ace permission. A command left atfalselets every connected player fire that code from chat, and unauthenticated player-triggered server actions are the single most common way FiveM servers get exploited.
The end keyword closes the function body. Lua does not use curly braces to mark where a block stops the way JavaScript or C# do. It uses the word end. A missing end is the single most common Lua error a beginner hits, so train your eye to pair every function with its end now.
Here is the flow in order. The server starts the resource and reads server.lua top to bottom. It hits RegisterCommand and registers the command, but it does not run the print yet. The print is sitting inside the handler, waiting. Later, when you type first_line_of_lua in the console, FiveM finds the matching command, runs the handler, and the print fires. Registering and running are two separate moments. That gap is the whole idea behind event-driven code, and almost everything you build in FiveM works this way: you register handlers up front, and they run later when something happens.
Why does nothing print the instant the resource restarts, only when you type the command?
Because the print lives inside the command handler, not at the top level of the file. On restart, FiveM runs server.lua once and reaches RegisterCommand, which only registers the command and stores the handler for later. The handler body, including the print, runs only when the command name is actually typed. If you wanted a line to appear the moment the resource starts, you would put the print outside the handler, at the top level of the file, the way the Anatomy of a resource lesson does it.
When you reach for this pattern
A command plus a print is the smallest useful tool in FiveM, and you will use it constantly even after you are far past beginner. Three real cases:
- A manual trigger while building. You are writing a feature and you want to fire one part of it on demand without waiting for the real game condition. A command is the fastest way to poke your code by hand.
- A debug probe. You suspect a value is wrong. Register a throwaway command that prints the value, type it whenever you want a reading, then delete it when you are done.
- An admin action. Heal, give an item, teleport. These are commands at heart, gated with the restricted flag so only staff can run them. You just built the skeleton every one of those shares.
If something went wrong
Stuck? Reset to a known-good state: re-paste the exact fxmanifest.lua and server.lua from Build it (overwriting whatever you have), then in the txAdmin Live Console run refresh; restart qu_first_line_of_lua and try the command again. refresh makes the server re-read your manifest; restart reloads the resource.
| Symptom | Fix |
|---|---|
attempt to call a nil value (global 'RegisterCommand') | The native name is misspelled. It is RegisterCommand with a capital R and a capital C. Lua is case sensitive, so registercommand will not resolve. |
')' expected near 'end' | A quote, comma, or paren is missing on the RegisterCommand line. Count the parentheses and make sure both the print string and the command name are wrapped in matching quotes. |
'end' expected (near <eof>) | The function has no closing end, or the final end and the closing paren of RegisterCommand got deleted. The block must finish with end, then the closing paren and the true flag. |
The command does nothing when a player runs it in chat | The restricted flag is true, so only the server console (and aces) may run it. Run first_line_of_lua from the txAdmin Live Console, not the in-game chat box (press T). |
What you can do now
- Read a Lua string and explain why the quotes are fences, not text.
- Use print to write a tagged line to the server console as a feedback probe.
- Explain that RegisterCommand registers a handler now and runs it later when the command is typed.
- Say what each of the three RegisterCommand arguments does, including why the restricted flag is true.
- Pair every function with its end and spot the error when one is missing.
Run it live
No server needed for this part. Edit the Lua below and press RUN to execute it in your browser on real Lua 5.4. Change the message, add a second print, and watch the output. The sandbox has no FiveM around it, so RegisterCommand and other natives are not available here. Plain Lua like print and strings run exactly as they would on your server.
Press RUN to execute.