FiveM officially supports Lua, JavaScript and C#. Choose the runtime that matches your framework, team skills and required libraries—not a supposed universal performance ranking. All three can call FiveM natives, handle events and expose resource APIs. The practical differences are the runtime boundary, package ecosystem, build workflow and the code already used by your dependencies.
Reviewed 10 August 2026 against the official Cfx.re documentation for the supported runtimes, scripting introduction E resource manifests. Runtime behavior can change, so verify those pages before starting a long-lived project.
FiveM language comparison
| Runtime | Good fit | Important boundary | Typical workflow |
|---|---|---|---|
| Lua | Existing Lua frameworks, compact resources and direct FiveM examples | CfxLua is a modified Lua 5.4 runtime, not an arbitrary system Lua installation | Edit source files and load them through the resource manifest |
| JavaScript | Teams using JavaScript/TypeScript and npm tooling | Client scripts do not receive browser or Node.js APIs; server scripts use FiveM’s Node runtime | Run source directly or compile/bundle TypeScript into manifest-listed JavaScript |
| C# | .NET teams, typed domain code and compiled projects | The resource must ship the assemblies and files expected by the Cfx.re runtime | Build from a Cfx.re template, then deploy the build output |
Lua: the direct framework path
Cfx.re documents CfxLua as a modified Lua 5.4 runtime. That matters when you compare FiveM code with older Lua tutorials: language features and runtime behavior should be checked against CfxLua, not inferred from a server’s operating-system package.
Lua is usually the least disruptive choice when the framework and neighboring resources are already written in Lua. You can keep events, exports and shared configuration in the same language and avoid adding a build step only for style. A small manifest can list separate client, server and shared scripts. Keep server-only secrets and authority checks out of client files even when both sides use Lua.
The short syntax makes event handlers easy to scan, but it does not replace interface design. Document every event payload, validate values on the server and avoid treating a client event as proof that money, inventory or permissions are valid.
JavaScript and TypeScript: know which side is running
The official JavaScript runtime guide describes ES2017 support and a critical client/server split. Client scripts run in FiveM’s client runtime and do not have browser APIs or Node.js APIs. Server scripts use a customized Node.js runtime. The default documented server version is Node.js 16; a resource can opt into Node.js 22 with node_version '22' In fxmanifest.lua.
Do not assume that a package working in an ordinary Node project also works in a FiveM client script. Put filesystem, database and server-side npm dependencies on the server boundary. For editor and TypeScript definitions, Cfx.re publishes the @citizenfx/client E @citizenfx/server packages. They improve type checking but do not grant APIs that the selected runtime lacks.
FiveM also documents thread-affinity constraints for some server-side native calls. When asynchronous Node code needs to return to the main game thread, follow the runtime guidance and use setImmediate where required. Test the built JavaScript that you actually deploy, including source maps and startup order, rather than only the TypeScript source.
C#: use the supported project shape
IL C# runtime documentation provides current project templates and build guidance. Start there instead of copying an old assembly layout from an unrelated .NET application. A C# resource normally has a project that references the supported CitizenFX assemblies, compiles its code and places the resulting files where the manifest can load them.
C# can be a strong fit when the team already uses .NET types, tooling and test practices. The tradeoff is operational: contributors and CI need the correct SDK and build command, and the deployed artifact must stay synchronized with its source. Record the template, target framework and release process in the repository so a server update is reproducible.
The shared model: manifests, natives, events and exports
Language choice does not change the resource contract. Every resource needs an fxmanifest.lua that declares metadata and the files to load. Client code runs for connected players; server code runs under FXServer. Shared files are delivered to both sides, so they must not contain credentials or server-only trust decisions.
- Natives expose game and platform functions. Check the current native reference and whether a native is client- or server-side.
- Eventi move messages within or across the client/server boundary. Treat network input as untrusted and validate it server-side.
- Exports publish functions for other resources. Keep names, parameters, return values and startup dependencies documented.
- Dipendenze belong in the manifest or server start order when another resource must be available first.
A mixed-language server is normal. The stable boundary is the documented event or export, not the implementation language behind it. That makes it possible to replace one resource without rewriting the whole stack.
How to choose for a real project
- Start with the framework. If the server depends on an established ESX, QBCore, Qbox or standalone resource, use its supported extension points and language conventions.
- List required libraries. Confirm that each database driver, UI bridge and package is compatible with the client or server runtime where it will run.
- Match the team. Prefer the language contributors can review, test and maintain after the original author leaves.
- Define the build. Lua may ship directly; TypeScript and C# usually need reproducible compilation and a clear output directory.
- Prototype the boundary. Prove one native call, one server-validated network event, one export and one dependency restart before building the full feature.
Minimal verification checklist
- Start the resource on a staging server and inspect both server and F8 client logs.
- Reconnect a clean client and restart the resource to expose missing files or ordering assumptions.
- Send invalid and unauthorized event payloads and confirm the server rejects them.
- Verify the documented Node version or .NET build output on the actual deployment host.
- Pin dependency versions and keep a rollback copy of the last working resource.
There is no evidence-based reason to crown one of the three FiveM coding languages as universally fastest or most popular for every resource. Select Lua, JavaScript/TypeScript or C# from the supported runtime facts, the surrounding framework and the maintenance cost your team can actually carry.
