Getting started

Prerequisites

  • Node.js ≥ 22 (FiveM's Cerulean runtime)
  • pnpm (recommended; npm/yarn work too)
  • Docker (for the MySQL + FiveM + Adminer compose stack)

Scaffold a new project

npm init merinaa my-server
cd my-server
pnpm install

The postinstall hook runs npx deepkit-type-install for you — Deepkit's TypeScript transformer needs to be injected before the first compile.

What you got:

my-server/
├── docker/                    MySQL + FiveM + Adminer compose
├── framework.config.yaml      runtime config (ENV-substituted at boot)
├── modules/
│   ├── merinaa.config.ts      app manifest
│   ├── config.ts              getDatabaseConfig / getEnvironment helpers
│   ├── tsconfig.{json,client.json}
│   ├── global.d.ts
│   └── hello/                 example module
│       ├── module.config.ts
│       ├── server/ (module, service, controller, guard, index)
│       ├── client/ (index, hello.client.ts)
│       └── ui/pages/HelloPage.tsx
├── resource/                  FiveM resource output (built)
│   └── fxmanifest.lua
├── scripts/
│   ├── build.js               generator → tsc → esbuild pipeline
│   └── generate-module-registry.js
├── ui/
│   ├── index.html
│   ├── main.tsx               imports @modules/.merinaa/ui
│   └── styles.css
├── package.json
├── tsconfig.base.json
├── vite.config.ts             @modules/* alias
├── tailwind.config.js
└── vitest.config.ts

First build

pnpm run build

That runs:

  1. scripts/generate-module-registry.js — reads your manifests, writes modules/.merinaa/{server,client,ui}.ts

  2. tspc — compiles TypeScript with the Deepkit reflection transformer

  3. esbuild — bundles server + client

  4. vite build — bundles NUI

Output lands in resource/.

Run it

cp .env.example .env        # MySQL credentials live here
pnpm run docker:up          # MySQL + FiveM
pnpm run docker:logs        # tail the server

Connect in FiveM to localhost:30120 and type /hello in chat — you should see the hello page with focus, movement and camera locked.

Dev loop

pnpm run dev

Watches merinaa.config.ts + every module.config.ts and re-runs the generator automatically. For UI hot-reload, open a second terminal:

pnpm run dev:ui

Next