Semantic search: native vector similarity in a multi-dialect ORM

Most ORMs stop short of vector similarity. The moment you need it, you drop to raw SQL, hand-writing distance expressions and working around dialect quirks outside your type-safe query API.
UQL 0.3 adds native semantic search to the regular query API, including automatic index migration for HNSW and IVFFlat indexes.
What it looks like
Section titled “What it looks like”const results = await pool.findMany(Article, { $select: { id: true, title: true }, $sort: { embedding: { $vector: queryEmbedding, $distance: 'cosine' } }, $limit: 10,});UQL generates the right SQL for your database:
SELECT "id", "title" FROM "Article"ORDER BY "embedding" <=> $1::vectorLIMIT 10SELECT `id`, `title` FROM `Article`ORDER BY VEC_DISTANCE_COSINE(`embedding`, VEC_FromText(?))LIMIT 10SELECT `id`, `title` FROM `Article`ORDER BY vec_distance_cosine(`embedding`, ?)LIMIT 10The same query works on every dialect, with no raw SQL or dialect checks in your code.
For MongoDB, UQL translates the same query into an Atlas $vectorSearch pipeline. The Atlas search index itself has to be created in Atlas; see the reference for details.
[ { "$vectorSearch": { "index": "embedding_index", "path": "embedding", "queryVector": ["..."], "numCandidates": 100, "limit": 10 } }]Entity setup
Section titled “Entity setup”Define your vector field and index; UQL handles schema generation, extension creation, and index building:
import { Entity, Id, Field, Index } from 'uql-orm';
@Entity()@Index(['embedding'], { type: 'hnsw', distance: 'cosine', m: 16, efConstruction: 64,})export class Article { @Id({ type: Number }) id?: number; @Field({ type: String }) title?: string;
@Field({ type: 'vector', dimensions: 1536 }) embedding?: number[];}For Postgres, UQL automatically emits CREATE EXTENSION IF NOT EXISTS vector. MariaDB has vector support built in; SQLite requires loading the sqlite-vec extension.
What else shipped
Section titled “What else shipped”$project returns the computed distance as a named field, typed with the exported WithDistance helper, without computing it twice. Alongside it came four distance metrics (cosine, l2, inner, l1), three vector types (vector, halfvec, sparsevec), and HNSW, IVFFlat and native vector indexes, each where the engine has it. Which engine has which lives in the reference, kept current as engines are added.
Why $sort?
Section titled “Why $sort?”Vector similarity search is fundamentally sorting by distance. UQL reuses the existing $sort API, which composes naturally with $where, $select, $limit, and regular sort fields:
const results = await pool.findMany(Article, { $where: { category: 'science' }, $sort: { embedding: { $vector: queryVec, $distance: 'cosine' }, title: 'asc', }, $limit: 10,});Get started
Section titled “Get started”npm i uql-ormIf you run into issues or missing features, open an issue on GitHub.
UQL is a JSON-native TypeScript ORM for Node.js, Bun and Deno. Supports PostgreSQL, PGlite, MySQL, MariaDB, MSSQL, SQLite, CockroachDB, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.