FiveM has three distinct runtime environments. Understanding their differences is essential for building compatible resources.
| Feature | Server | Client | Views (NUI) |
|---|---|---|---|
| Runtime | Node.js | Neutral JS | Web Browser |
| Platform | node |
neutral |
browser |
| Node.js APIs | Available | NOT available | NOT available |
| Web APIs | NOT available | NOT available | Available |
| FiveM APIs | Available | Available | Limited |
| GTA Natives | NOT available | Available | NOT available |
| External packages | Supported | NOT supported | N/A (separate build) |
The server runs in a full Node.js environment.
- All Node.js APIs (
fs,path,http,crypto,child_process, etc.) - FiveM server-side APIs and events
- External packages from
node_modules - Filesystem access
- Network requests
- GTA natives (server has no game context)
- Web APIs (
DOM,window, etc.)
server: {
platform: 'node',
format: 'cjs',
target: 'es2020',
external: ['typeorm', 'pg'], // Optional
}When server.external is used, OpenCore defaults to sandbox-safe isolated dependency installation for FiveM/RedM:
build: {
dependencyResolution: {
mode: 'isolated',
packageManager: 'auto',
verifySandboxPaths: true,
allowInstallScripts: false,
},
server: {
external: ['typeorm', 'pg', '@prisma/adapter-pg'],
},
}The built resource gets its own physical node_modules and minimal package.json. OpenCore resolves dependency versions from the resource package.json, then the root package.json, then installed package metadata. It refuses to install latest silently.
Legacy dependencyResolution.mode: 'symlink' remains available as explicit opt-in, but it may fail under the FXServer Node.js 22 filesystem sandbox.
Experimental shared dependency mode is available when you want all resources to read runtime packages from one generated resource:
build: {
dependencyResolution: {
mode: 'shared-resource',
sharedResourceName: '__opencore_deps',
verifySandboxPaths: true,
},
server: {
external: ['typeorm', 'pg', '@prisma/adapter-pg'],
},
}OpenCore generates __opencore_deps and rewrites external imports at bundle time through an esbuild virtual module that uses GetResourcePath('__opencore_deps'). This mode is experimental because FXServer sandbox rules may still restrict cross-resource reads under Node.js 22.
Experimental bundle mode is available for pure JavaScript packages:
build: {
dependencyResolution: {
mode: 'bundle',
},
server: {
external: ['nanoid'],
},
}In this mode, server.external marks packages that should be compatibility-checked and then bundled into each resource. OpenCore rejects native packages and warns about dynamic require() usage. Do not use bundle mode for Prisma, native modules, packages that load runtime assets, or packages that depend on dynamic loading.
The client runs in a neutral JavaScript environment inside the game.
- FiveM client-side APIs and events
- GTA V natives (game functions)
- Pure JavaScript/ES2020
- Node.js APIs (
fs,path,http, etc.) - Web APIs (
DOM,fetch,localStorage,window, etc.) - Filesystem access
- External packages (everything must be bundled)
client: {
platform: 'neutral',
format: 'iife',
target: 'es2020',
// external: NOT supported - all deps must be bundled
}If you configure client.external, it will be ignored with a warning.
Views/NUI run in an embedded web browser (Chromium-based).
- Web APIs (
DOM,fetch,localStorage,window, etc.) - CSS, HTML, JavaScript
- Web frameworks (React, Vue, Svelte, etc.)
- Communication with client via
SendNUIMessage/RegisterNUICallback
- Node.js APIs
- FiveM APIs (must communicate via NUI callbacks)
- GTA natives
The embedded browser has version limitations that are not fully documented. Some modern Web APIs may not be available. Test your NUI on actual FiveM to ensure compatibility.
Known considerations:
- Older Chromium version than current Chrome
- Some CSS features may not work
- Some modern JS APIs may be missing
Views are built separately using web bundlers:
views: {
path: './core/views',
framework: 'vite', // or use 'vanilla' only for simple JS/TS views
}┌─────────────────────────────────────────────────────────────┐
│ SERVER │
│ (Node.js) │
│ │
│ - Database access │
│ - Business logic │
│ - External APIs │
└──────────────────────┬──────────────────────────────────────┘
│
emitNet
│
┌──────────────────────▼──────────────────────────────────────┐
│ CLIENT │
│ (Neutral JS) │
│ │
│ - GTA natives │
│ - Game interaction │
│ - Player input │
└──────────────────────┬──────────────────────────────────────┘
│
SendNUIMessage / RegisterNUICallback
│
┌──────────────────────▼──────────────────────────────────────┐
│ VIEWS (NUI) │
│ (Web Browser) │
│ │
│ - User interface │
│ - HTML/CSS/JS │
│ - Web frameworks │
└─────────────────────────────────────────────────────────────┘
These packages use C++ bindings and will NOT work on the client:
| Package | Alternative |
|---|---|
bcrypt |
bcryptjs |
argon2 |
hash.js, js-sha3 |
sharp |
jimp |
canvas |
pureimage |
sqlite3 |
sql.js |
better-sqlite3 |
sql.js |
The CLI will warn you if it detects incompatible packages. (nothing is promised)
- Server: Use for heavy computation, database access, external APIs, source of truth
- Client: Keep minimal - only game interaction and natives
- Views: Standard web development, but test on FiveM
- Bundle client deps: NEVER use
externalfor client - Test on actual FiveM: Some packages may have hidden dependencies