Engineering
Writing FiveM resources in TypeScript
Build FiveM resources with TypeScript: the @citizenfx/client and @citizenfx/server typings, bundling with esbuild into client and server files, the fxmanifest, Node.js 16 and optional Node 22 on the server, events, exports typing with CitizenExports, and when TypeScript is worth it.
Overview
FiveM runs JavaScript natively on both client and server, and TypeScript compiles to it. For larger resources — or teams used to web development — TypeScript’s types, imports and npm ecosystem are a real advantage over plain Lua. The setup is a small build step.
01Project setup
npm init -y
npm install --save-dev typescript esbuild @citizenfx/client @citizenfx/servermy_resource/
fxmanifest.lua
package.json
build.mjs
src/client/main.ts
src/server/main.ts
dist/ -- generated02Bundling
import { build } from 'esbuild';
await build({ entryPoints: ['src/client/main.ts'], bundle: true, outfile: 'dist/client.js', platform: 'browser', target: 'es2017' });
await build({ entryPoints: ['src/server/main.ts'], bundle: true, outfile: 'dist/server.js', platform: 'node', target: 'node16' });fx_version 'cerulean'
game 'gta5'
client_script 'dist/client.js'
server_script 'dist/server.js'
-- node_version '22' -- opt in to Node.js 22 for server scriptsThe client target matches the ES2017 standard library FiveM’s client runtime provides. If you opt in to Node 22, raise the server target accordingly.
Writing code
onNet('fishmarket:sell', () => {
const src = global.source;
const ped = GetPlayerPed(String(src));
const [x, y, z] = GetEntityCoords(ped);
console.log(`player ${src} at ${x.toFixed(1)}, ${y.toFixed(1)}, ${z.toFixed(1)}`);
});
exports('getPrice', (item: string) => (item === 'fish' ? 45 : 0));RegisterCommand('sell', () => {
emitNet('fishmarket:sell');
}, false);Events: on/onNet to listen, emit/emitNet to trigger. Server natives take player IDs as strings in the typings. Security rules are the same as in Lua — see secure server events.
Typing exports
declare global {
interface CitizenExports {
fishmarket: {
getPrice(item: string): number;
};
}
}
export {};When TypeScript is worth it
- Large resources with shared data types between client, server and NUI.
- Teams that already write TypeScript for the web.
- Server code that benefits from npm packages (HTTP clients, validation).
- Frameworks with JS APIs, such as ox_core’s npm package — see ox_core overview.
For small scripts, Lua remains quicker to write and is what most tutorials use — see choosing a language.
Frequently asked questions
Can I write FiveM scripts in TypeScript?
Yes. Compile or bundle TypeScript to JavaScript and list the output in the fxmanifest.
Which Node.js version does FiveM use?
Node.js 16 on the server by default; add node_version '22' to the manifest for Node 22.
Can I use npm packages in FiveM?
On the server, yes (bundled or from node_modules). On the client, only pure JS without browser or Node APIs.
Where do FiveM TypeScript typings come from?
The official @citizenfx/client and @citizenfx/server npm packages.
Need this built, not just explained?
Ten years of FiveM work, from Lua to NUI
Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.
Related guides
- Getting startedLua, C# or JavaScript: which language should you learn for FiveM?Learn Lua first. It is what almost every public FiveM resource and every major framework (ESX, QBCore, Qbox, ox) is written in, so it is the language you will read, copy and debug most. Add JavaScript or TypeScript when you build NUI interfaces or want the npm ecosystem on the server, and consider C# if you already know .NET and want strong typing.
- EngineeringWriting FiveM resources in C#Install the templates with dotnet new -i CitizenFX.Templates, create a resource with dotnet new cfx-resource, and build with the included build.cmd to get client and server DLLs in dist. Each script class inherits BaseScript, registers events through EventHandlers[...], and calls natives via using static CitizenFX.Core.Native.API. Link dist into your resources folder and ensure it.
- Getting startedSetting up VS Code for FiveM scriptingInstall the Lua extension (Lua Language Server by sumneko/LuaLS). Clone Overextended’s fivem-lls-addon — the replacement for the discontinued CfxLua IntelliSense extension — into a folder for Lua addons, point workspace.userThirdParty at that folder in a .luarc.json, and add ox_lib to workspace.library. For JavaScript/TypeScript, install @citizenfx/client and @citizenfx/server typings.
- FrameworksWhat ox_core is and how scripts use itox_core manages users, characters, groups, bank accounts and persistent vehicles. In Lua, load it with local Ox = require '@ox_core.lib.init' and use Ox.GetPlayer(source) (an OxPlayer with charId, getGroup…), Ox.GetCharacterAccount(charId) for bank accounts (addBalance, removeBalance, transferBalance), and Ox.CreateVehicle for owned vehicles. JavaScript/TypeScript resources use the @overextended/ox_core npm package. Money in hand and items are ox_inventory items.