Skip to content
NewFrom Mongoose to SQL: migrating MongoDB to PostgreSQL7 min read

JSON-native TypeScript ORM

UQL queries SQL databases and MongoDB with plain, type-safe JSON. No codegen, no query builder.

Using a coding agent? Copy the setup prompt

import { pool } from './uql.config.js';
import { User } from './entities.js';
await pool.findMany(User, {
// the entity class types every key
$select: { id: true, emial: true },
// same three levels deep
$populate: { posts: { $select: { titel: true } } },
// and operators against the column type
$where: { loginCount: { $like: 3 } },
});

A query is a plain object: no builder to chain, no operators to import. The compiler checks every key at any depth, and the operators ($in, $gte, $or, …) are MongoDB’s. The red lines in the editor above are real tsc errors against the published types: a misspelled field, the same typo inside a populated relation, and an operator the column’s type does not allow.

Entities are plain classes with standard decorators, or plain data with defineEntity when you want no decorators. Both are typed the same, they mix in one project, and neither needs codegen. Checking reaches into JSON dot-paths too.

A query is data, so the browser can send it over HTTP, typed the same as on the server:

import { createClientQuerier, httpTransport } from 'uql-orm/browser';
const client = createClientQuerier(httpTransport('/api/v1'));
const users = await client.findMany(User, {
$select: { id: true, email: true },
$where: { email: { $endsWith: '@uql-orm.dev' } },
});

The API runs each write in a transaction, takes what each definition’s wire lets a client read and write, and mounts on Hono, Elysia, Next.js, Express, Bun or Workers, or inside a tRPC procedure. See the API and the client.

Compare it feature by feature and on type safety.