Choosing a runtime: Lua, JavaScript, or C#
This is a decision lesson, not a heavy build. FiveM does not run one language. It runs three: Lua 5.4, JavaScript on Node, and C# on .NET. Most of what you will read, fork, and ship is Lua, which is why this course teaches Lua. But you should know the other two exist, how the manifest declares them, and the narrow cases where reaching past Lua is the right call. The build at the end is small on purpose: one JavaScript server script printing alongside a Lua one, so you see with your own eyes that they coexist in the same resource.
The three runtimes
FiveM exposes the same scripting platform through three language runtimes. They all see the same natives, the same events, the same resource model. The difference is the language you write and the engine that runs it.
Lua 5.4: the default this course teaches
Lua is the shortest route through this course. There is no project build step: save the file and restart the resource. ESX, QBCore, Qbox, and the Overextended resources all publish Lua-facing APIs, so Lua lets you read the examples used later without changing languages. No reliable official statistic says what percentage of public resources use each runtime, so choose from the code and dependencies you actually plan to maintain.
One accuracy note for 2026: you do not add a lua54 'yes' line to the manifest anymore. The official docs mark that directive deprecated as of June 2025: Lua 5.3 was removed and every Lua script now runs on 5.4, so the line is a no-op and there is nothing to opt into.
JavaScript on Node: for NUI-heavy work and JS developers
FiveM ships a Node runtime, so a .js file declared as a client_script or server_script runs with no compile step, the same as Lua. Two honest reasons to reach for it. First, your NUI front end is already HTML, CSS, and JavaScript, so a JS server or client script lets you share types and mental model across the boundary instead of switching languages mid-resource. Second, if your team already lives in JavaScript, the ramp is shorter than learning Lua from zero.
The one manifest detail that trips people up: you pin the Node major version with a node_version line, for example node_version '22'. Leave it off and the server uses its built-in default, a customized Node.js 16.x at the time of writing; pinning '22' opts into the newer runtime and keeps the behaviour you tested stable across server updates.
C# on .NET: compiled, for large or enterprise systems
C# does not run from source. You write .cs files, compile them with the .NET SDK into a .dll, and the manifest loads that compiled assembly rather than the source. At a high level the flow is: write C# referencing the CitizenFX runtime, run a build (typically dotnet build) that produces a .net.dll, and declare that dll in the manifest as a client or server assembly. The payoff is static typing, real IDE refactoring, and structure that holds up across a large codebase. The cost is a build step between every change and a heavier toolchain. For a single feature script this is overkill. For a large team shipping an enterprise-scale system where compile-time safety earns its keep, it is a reasonable choice.
Keep reading the full lesson
Sign in to start, then unlock every step of this lesson and the full FiveM School with a membership.
- Build it
- How it works
- Common mistakes
- What you can do now
- Try it yourself
The remainder of Choose a runtime: Lua, JS, or C# is available to FiveM School members.