OpenCore is a TypeScript multiplayer runtime framework targeting FiveM via an adapter.
It is not a gamemode or RP framework. It provides:
- A stable execution model (server and client)
- Dependency Injection and metadata-driven wiring
- An event/command system
- Security primitives (validation, access control, rate limiting)
License: MPL-2.0
Discord Community | Docs | OpenCore CLI
pnpm add @open-core/framework reflect-metadata tsyringe zod uuidThis framework uses TypeScript decorators. Ensure your project has decorators enabled.
The package exposes subpath entry points:
@open-core/framework(root)@open-core/framework/server@open-core/framework/client
Most projects will import the Server/Client namespaces:
import { Server } from '@open-core/framework/server'OpenCore follows a Ports & Adapters (Hexagonal) architecture.
- Kernel (
src/kernel): engine-agnostic infrastructure (DI, logger, metadata scanning) - Runtime (
src/runtime): multiplayer execution model (controllers, processors, security, lifecycle) - Adapters (
src/adapters): platform integration (FiveM, Node testing)
The runtime never auto-detects the platform. Adapters are selected explicitly at bootstrap time.
Each instance runs in exactly one mode configured via Server.init():
CORE: authoritative runtime. Typically provides identity/auth/players via exports.RESOURCE: a normal FiveM resource using CORE as provider for some features.STANDALONE: a self-contained runtime (useful for tooling, simulations, or small servers).
Initialize the server runtime:
import { Server } from '@open-core/framework/server'
await Server.init({
mode: 'CORE'
})Some features require providers (depending on your mode and configuration). Configure them before calling init():
import { Server } from '@open-core/framework/server'
Server.setPrincipalProvider(MyPrincipalProvider)
Server.setSecurityHandler(MySecurityHandler)
Server.setPersistenceProvider(MyPlayerPersistence)
Server.setNetEventSecurityObserver(MyNetEventSecurityObserver)OpenCore uses a decorator + processor pattern.
Decorators store metadata with Reflect.defineMetadata(). During bootstrap, the MetadataScanner reads metadata and processors register handlers.
import { Server } from '@open-core/framework/server'
import { z } from 'zod'
const TransferSchema = z.tuple([z.coerce.number().int().positive(), z.coerce.number().min(1)])
@Server.Controller()
export class BankController {
@Server.Command({
command: 'transfer',
usage: '/transfer <id> <amount>',
schema: TransferSchema,
})
@Server.Guard({ rank: 1 })
@Server.Throttle(1, 2000)
async transfer(player: Server.Player, args: z.infer<typeof TransferSchema>) {
const [targetId, amount] = args
player.emit('chat:message', `transfer -> ${targetId} (${amount})`)
}
}@OnNet() handlers always receive Player as the first parameter.
import { Server } from '@open-core/framework/server'
import { z } from 'zod'
const PayloadSchema = z.object({ action: z.string(), amount: z.number().int().positive() })
@Server.Controller()
export class ExampleNetController {
@Server.OnNet('bank:action', { schema: PayloadSchema })
async onBankAction(player: Server.Player, payload: z.infer<typeof PayloadSchema>) {
player.emit('chat:message', `action=${payload.action} amount=${payload.amount}`)
}
}@Guard({ rank })or@Guard({ permission })@Throttle(limit, windowMs)@RequiresState({ missing: [...] })
Tests run with Vitest.
pnpm test
pnpm test:unit
pnpm test:integration
pnpm test:coverageNote: pnpm test does not run benchmarks.
There are two benchmark suites:
- Core benchmarks (Tinybench)
- Load benchmarks (Vitest project
benchmark)
pnpm bench:core
pnpm bench:load
pnpm bench:allThese values are a small extract from a recent local run (Dec 22, 2025). Results vary by machine.
- Core
- Decorators - Define metadata (Command):
~5.72M ops/sec(mean0.17μs) - EventBus - Multiple event types:
~2.01M ops/sec(mean0.50μs) - Dependency Injection (simple resolve):
~1.7M ops/sec
- Decorators - Define metadata (Command):
- Load
- Net Events - Simple (10 players):
~28.85K ops/sec(p950.25ms) - Net Events - Concurrent (500 players):
~1.18M ops/sec(p950.40ms) - Commands (validated, ~500 players):
~14M ops/sec
- Net Events - Simple (10 players):
Full reports and methodology are available in benchmark/README.md.
Benchmark reports are generated under benchmark/reports/.
pnpm bench:allgenerates aggregated reports (text/json/html)- Load metrics used by load benchmarks are persisted in
benchmark/reports/.load-metrics.json
For details about the benchmark system, see benchmark/README.md.
pnpm build
pnpm watch
pnpm lint
pnpm lint:fix
pnpm formatOpenCore is designed to be extended via separate packages/resources.
@open-core/identity: identity and permission system
MPL-2.0. See LICENSE.