Uql
The fastest TypeScript ORM
Install / Use
/learn @rogerpadilla/UqlREADME
<a href="https://uql-orm.dev"><img src="assets/logo.svg" alt="uql" width="80" /></a>
UQL is the best ORM for TypeScript and modern JavaScript designed to be fast, safe, and easy to integrate into any application — especially AI and data‑heavy workloads. Built with a unified API across SQL and MongoDB.
const results = await querier.findMany(User, {
$select: { name: true, profile: { $select: { picture: true } } },
$where: { name: { $istartsWith: 'a' }, posts: { tags: { name: 'typescript' } } },
$sort: { createdAt: 'desc' },
$limit: 10,
});
Quick Start
npm install uql-orm pg
import { PgQuerierPool } from 'uql-orm/postgres';
const pool = new PgQuerierPool({ host: 'localhost', database: 'app' });
const users = await pool.withQuerier((querier) => querier.findMany(User, { $limit: 10 }));
For production setup and migrations, jump to:
Note: For explicit lifecycle control, use manual
getQuerier()+release()(shown in Core Query Pattern).
Guide Map
Core path:
- 1. Install
- 2. Define your Entities
- 3. Set up a pool
- 4. Manipulate the Data
- 5. Migrations & Synchronization
Advanced and operations:
- Semantic Search
- JSON Operators & Relation Filtering
- Thread-Safe Transactions
- 6. Logging & Monitoring
- Deep Dive: Tests & Technical Resources
Features
| Feature | Why it matters |
| :--- | :--- |
| Intelligent Querying | Deep auto-completion for operators and relations at any depth—no more guessing property names. |
| Serializable JSON | Query objects are valid JSON, which makes them straightforward to transport over HTTP/gRPC/WebSockets. |
| Unified Dialects | Write once, run anywhere. Seamlessly switch between PostgreSQL, MySQL, MariaDB, SQLite, and MongoDB. |
| Naming Strategies | No more camelCase vs snake_case headaches. Map your code to your database automatically. |
| Smart SQL Engine | Zero-allocation SQL generation with top-ranked results in our open benchmark. |
| Thread-Safe by Design | Protect your data integrity with centralized task queues and the @Serialized() decorator. |
| Declarative Transactions | Clean @Transactional() decorators that work beautifully with modern DI frameworks like NestJS. |
| Lifecycle Hooks | Automate validation, timestamps, and computed logic with intuitive class-based decorators. |
| Aggregate Queries | Real-time analytics with GROUP BY, HAVING, and native math operators across all dialects. |
| Semantic Search | Native vector similarity search. Rank results by meaning using standard ORM operators. |
| Cursor Streaming | Process millions of rows with a stable memory footprint using native driver-level cursors. |
| Modern & Versatile | Pure ESM, high-res timing, built-in soft-delete, and first-class JSON/JSONB support. |
| Database Migrations | Entity-First synchronization. DDL is auto-generated by diffing your code against the live DB. |
| Logging & Monitoring | High-visibility debugging with slow-query detection and high-contrast terminal output. |
| Fullstack Bridge | Speak to your database from the browser securely. First-party HttpQuerier removes API boilerplate. |
1. Install
Install the core package and the driver for your database:
# Core
npm install uql-orm # or bun add / pnpm add
Supported Drivers (pick according to your database)
| Database | Command |
| :--- | :--- |
| PostgreSQL (incl. Neon, Cockroach, Yugabyte) | npm install pg |
| MySQL (incl. TiDB, Aurora) | npm install mysql2 |
| MariaDB | npm install mariadb |
| SQLite | npm install better-sqlite3 |
| LibSQL (incl. Turso) | npm install @libsql/client |
| MongoDB | npm install mongodb |
| Cloudflare D1 | Native (no driver needed) |
| Bun SQL Native (Incl. Postgres, MySQL, SQLite) | Native (no driver needed) |
TypeScript Configuration
Ensure your tsconfig.json is configured to support decorators and metadata:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Note: UQL is Modern Pure ESM — ensure your project's
modulesupports ESM imports (e.g.,NodeNext,ESNext,Bundler).
2. Define your Entities
Annotate your classes with decorators. UQL's engine uses this metadata for both type-safe querying and precise DDL generation.
Core Decorators
| Decorator | Purpose |
| :--- | :--- |
| @Entity() | Marks a class as a database table/collection. |
| @Id() | Defines the Primary Key with support for onInsert generators. |
| @Field() | Standard column. Use { references: ... } for Foreign Keys. |
| @Index() | Defines a composite or custom index on one or more columns. |
| @OneToOne | Defines a one-to-one relationship. |
| @OneToMany | Defines a one-to-many relationship. |
| @ManyToOne | Defines a many-to-one relationship. |
| @ManyToMany | Defines a many-to-many relationship. |
| @BeforeInsert | Lifecycle hooks fired around database operations. |
| @AfterLoad | Lifecycle hook fired after loading entities. |
Type Abstraction: Logical vs. Physical
UQL separates the intent of your data from its storage. Both properties are optional; if omitted, UQL performs a best-effort inference using the TypeScript types from your class.
| Property | Purpose | Values |
| :--- | :--- | :--- |
| type | Logical Type (Abstraction). Used for runtime behavior and automatic SQL mapping. | String, Number, Boolean, Date, BigInt, or semantic strings: 'uuid', 'json', 'vector', 'halfvec', 'sparsevec'. |
| columnType | Physical Type (Implementation). Highest Priority. Bypasses UQL's inference for exact SQL control. | Raw SQL types: 'varchar(100)', 'decimal(10,2)', 'smallint', etc. |
// Automatic inference from TypeScript types
@Field() name?: string; // → TEXT (Postgres), VARCHAR(255) (MySQL)
@Field() age?: number; // → INTEGER
@Field() isActive?: boolean; // → BOOLEAN
@Field() createdAt?: Date; // → TIMESTAMP
// Semantic types - portable across all databases
@Field({ type: 'uuid' }) // → UUID (Postgres), CHAR(36) (MySQL), TEXT (SQLite)
externalId?: string;
@Field({ type: 'json' }) // → JSONB (Postgres), JSON (MySQL), TEXT (SQLite)
metadata?: Json<{ theme?: string }>;
// Logical types with constraints - portable with control
@Field({ type: 'varchar', length: 500 })
bio?: string;
@Field({ type: 'decimal', precision: 10, scale: 2 })
price?: number;
// Exact SQL type - when you need dialect-specific control
@Field({ columnType: 'smallint' })
statusCode?: number;
import { v7 as uuidv7 } from 'uuid';
import { Entity, Id, Field, OneToOne, OneToMany, ManyToOne, ManyToMany, type Relation, type Json } from 'uql-orm';
@Entity()
export class User {
@Id({ type: 'uuid', onInsert: () => uuidv7() })
id?: string;
@Field({
index: true,
})
name?: string;
@Field({
unique: true,
comment: 'User login email',
})
email?: string;
@OneToOne({
entity: () => Profile,
mappedBy: (profile) => profile.user,
cascade: true,
})
profile?: Relation<Profile>;
@OneToMany({
entity: () => Post,
mappedBy: (post) => post.author,
})
posts?: Relation<Post>[];
}
@Entity()
export class Profile {
@Id({ type: 'uuid', onInsert: () => uuidv7() })
id?: string;
@Field()
bio?: string;
@Field({ references: () => User, foreignKey: 'fk_profile_user' })
userId?: string;
@OneToOne({ entity: () => User })
user?: User;
}
@Entity()
export class Post {
@Id()
id?: number;
@Field()
title?: string;
@Field({ references: () => User })
authorId?: string;
@ManyToOne({ entity: () => User })
author?: User;
@ManyToMany({
entity: () => Tag,
through: () => PostTag,
})
tags?: Tag[];
}
@Entity()
export class Tag {
@Id({ type: 'uuid', onInsert: () => uuidv7() })
id?: string;
@Field()
name?: string;
}
@Entity()
export class PostTag {
@Id({ type: 'uuid', onInsert: () => uuidv7() })
id?: string;
@Field({ references: () => Post })
postId?: number;
@Field({ references: () => Tag })
tagId?: string;
}
Note: Use the
Relation<T>utility type for relationship properties. It prevents TypeScript circular dependency errors while maintaining full type-safety throughout your app.
