Why I built this
I really enjoy experimenting in the FiveM ecosystem — the runtime has its own unique challenges that make development interesting. One pain point I kept running into was writing raw SQL queries for database operations. I wanted a cleaner, type-safe way to interact with MySQL, so I built aq-orm to simplify data querying and bring a modern DX to FiveM development.
What it does
aq-orm is a lightweight ORM designed specifically for FiveM servers using oxmysql as the database driver. It provides a fluent, chainable query builder with full TypeScript type inference from your schema definitions.
Schema definition
Define your tables with type-safe column builders:
import { table, int, varchar, boolean, timestamp } from "@aquapha/aq-orm";
const users = table("users", {
id: int("id").primaryKey().autoIncrement(),
name: varchar("name", 255).notNull(),
email: varchar("email").notNull().unique(),
active: boolean("active").default(true),
createdAt: timestamp("created_at").notNull(),
});
TypeScript types are inferred directly from the schema — no manual type definitions needed:
import type { Infer } from "@aquapha/aq-orm";
type User = Infer<typeof users>;
// { id: number | null; name: string; email: string; active: boolean; createdAt: Date }
Query builder
Queries are built with a fluent API that reads naturally:
const activeUsers = await db
.select(users)
.where(eq(users.columns.active, true))
.orderBy(users.columns.createdAt, "DESC")
.limit(10)
.execute();
It supports joins, aggregates, group by, transactions, and even MySQL-specific functions like JSON_OBJECT and JSON_EXTRACT.
Key features
- Type-safe schemas — column types map directly to TypeScript types
- Fluent query builder — select, insert, update, delete with chainable methods
- Conditions —
eq,gt,like,inArray,between, and more - Aggregates —
count,sum,avg,min,max - Joins — inner, left, and self-joins with table aliases
- Transactions — batch multiple operations atomically
- Raw SQL escape hatch — tagged template literals with parameterized queries