Skip to content

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

One $vector sort compiled to PostgreSQL, MariaDB, SQLite and MongoDB Atlas syntax side by side

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.

You write
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::vector
LIMIT 10

The 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
}
}
]

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.

$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.

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,
});
Terminal window
npm i uql-orm

If 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.