UQL is the perfectionist ORM: serializable queries, no codegen, and one API across PostgreSQL, MySQL, SQLite, MariaDB, and MongoDB. Define entities once, query everywhere.
await querier.findMany(User, {
$select: { id: true, email: true },
$where: { email: { $endsWith: '@uql-orm.dev' } },
$limit: 10,
});Full docs: uql-orm.dev
- Queries are data, not method chains. A UQL query is a plain JSON object. Build them dynamically, store them, or send them from client to server without a DSL.
- No codegen, no build step. Entities are TypeScript classes, so your code is the schema. No
.prismafiles or generated clients to keep in sync. - One API everywhere. The same syntax runs on PostgreSQL, MySQL, MariaDB, SQLite, LibSQL, Neon, Cloudflare D1, MongoDB, and Bun's native SQL.
- Fast by design. Fastest in all 8 categories of our open benchmark: on average ~2.1× faster than the runner-up, reaching over 3.9M ops/s on SELECTs.
| Feature | Docs |
|---|---|
| Unified API across SQL + MongoDB | Install |
| Type-safe queries with autocomplete | Querying |
| Entity-first migrations & autoSync | Migrations |
| Soft-delete, lifecycle hooks, relations | Entities |
| Query filters, multi-tenancy & row-level security | Filters · Multi-tenancy |
| Aggregate queries, grouping, HAVING | Aggregate |
| Batch inserts with reliable IDs on every database | Insert IDs |
| Semantic search & vector similarity | Semantic Search |
| Parallel reads & raw SQL on the pool | Parallel reads · Raw SQL |
| Streaming, transactions | Streaming · Transactions |
| REST API from your entities (any framework) | HTTP |
| Typed browser client, NestJS module | Browser · NestJS |
npm install uql-orm pg # or mysql2, mariadb, better-sqlite3, mongodb, @libsql/clientSupports PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, LibSQL/Turso, Neon, MongoDB, Cloudflare D1, and Bun SQL.
Declare your classes with decorators. UQL uses this metadata for type-safe querying and DDL generation.
import { v7 as uuidv7 } from 'uuid';
import { Entity, Id, Field, OneToOne, OneToMany, type Relation } from 'uql-orm';
@Entity()
export class User {
@Id({ type: 'uuid', onInsert: () => uuidv7() })
id?: string;
@Field({ index: true, unique: true })
email?: string;
@OneToOne({ entity: () => Profile, mappedBy: (p) => p.user, cascade: true })
profile?: Relation<Profile>;
@OneToMany({ entity: () => Post, mappedBy: (p) => p.author })
posts?: Relation<Post>[];
}Imperative API:
defineEntity(User, { fields: { id: { type: 'uuid', isId: true } }, ... }). No decorators needed. See Imperative Definition.
await querier.findMany(User, {
$select: { id: true, name: true },
$where: { email: { $endsWith: '@uql-orm.dev' } },
$limit: 10,
});25+ comparison operators ($eq, $in, $between, $like, $elemMatch), logical operators ($and, $or, $not, $nor), and type-safe JSON/JSONB dot-notation queries.
Independent reads run directly on the pool - each call gets its own connection, so Promise.all fans out in parallel:
const [users, total] = await Promise.all([
pool.findMany(User, { $where: { status: 'active' } }),
pool.count(User, {}),
]);Querying · Parallel reads · Operators · JSON
Functional pool.transaction() or @Transactional() decorator with centralized serialization:
const userId = await pool.transaction(async (q) => {
const id = await q.insertOne(User, { email: 'a@b.com' });
await q.insertOne(Profile, { userId: id, bio: '...' });
return id;
});Entity-first migrations: modify TypeScript classes, UQL auto-generates DDL by diffing code against the live database:
npx uql-migrate generate:entities add_user_nickname # generate from entities
npx uql-migrate up # apply
npx uql-migrate drift:check # detect driftSafe autoSync() mode adds new tables/columns and blocks destructive changes in development.
AI meeting recorder and video summarizer for Zoom, Meet, Teams, and more. Generates instant summaries with action items in 45+ languages.