> Every UQL docs page, as Markdown: https://uql-orm.dev/llms.txt
> The same docs over MCP: https://uql-orm.dev/mcp
> Before writing UQL code, read the skill: https://uql-orm.dev/.well-known/agent-skills/uql-orm/SKILL.md

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

> Native vector similarity search on PostgreSQL, MariaDB, SQLite and MongoDB Atlas through one type-safe query API, with automatic index migration.

Source: https://uql-orm.dev/blog/semantic-search

Most ORMs stop short of vector similarity. Once you need it, you drop to raw SQL: hand-written distance expressions and dialect quirks, outside your type-safe query API.

UQL 0.3 adds semantic search to the regular query API, with automatic migration of HNSW and IVFFlat indexes.

> **Updated September 2026**
>
> Vector search has since reached CockroachDB, libSQL, Turso and SQL Server 2025, and gained [`$near`](https://uql-orm.dev/querying/semantic-search.md#distance-predicate) to filter by distance and [`$candidates`](https://uql-orm.dev/querying/semantic-search.md#tuning-recall) to tune recall. The [reference](https://uql-orm.dev/querying/semantic-search.md) has the current per-engine detail.

## What it looks like

```ts title="You write"
const queryVec = await embed('How do vector indexes work?');

const results = await pool.findMany(Article, {
  $select: { id: true, title: true },
  $sort: { embedding: { $vector: queryVec, $distance: 'cosine' } },
  $limit: 10,
});
```

UQL generates each database’s SQL:

PostgreSQL:

```sql
SELECT "id", "title" FROM "Article"
ORDER BY "embedding" <=> $1::vector
LIMIT 10
```

MariaDB:

```sql
SELECT `id`, `title` FROM `Article`
ORDER BY VEC_DISTANCE_COSINE(`embedding`, VEC_FromText(?))
LIMIT 10
```

SQLite:

```sql
SELECT `id`, `title` FROM `Article`
ORDER BY vec_distance_cosine(`embedding`, ?)
LIMIT 10
```

One query for every dialect, with no raw SQL or dialect checks in your code.

On MongoDB, the same query becomes an Atlas `$vectorSearch` pipeline. The search index itself is created in Atlas; the [reference](https://uql-orm.dev/querying/semantic-search.md) has the details.

MongoDB Atlas:

```json
[
  {
    "$vectorSearch": {
      "index": "embedding_index",
      "path": "embedding",
      "queryVector": ["..."],
      "numCandidates": 100,
      "limit": 10
    }
  }
]
```

## Entity setup

Declare the vector field and its index; UQL creates the column, the extension and the index:

```ts
import { Entity, Id, Field, Index } from 'uql-orm';

@Entity()
@Index((article) => [article.embedding], {
  type: 'hnsw',
  distance: 'cosine',
  m: 16,
  efConstruction: 64,
})
export class Article {
  @Id({ type: Number }) id?: number;
  @Field({ type: String }) title?: string | null;
  @Field({ type: String }) category?: string | null;

  @Field({ type: 'vector', dimensions: 1536 })
  embedding?: number[] | null;
}
```

On Postgres, UQL emits `CREATE EXTENSION IF NOT EXISTS vector`. MariaDB has vectors built in; SQLite needs the [sqlite-vec](https://github.com/asg017/sqlite-vec) extension loaded.

## What else shipped

`$project` returns the computed distance as a named field, without computing it twice, typed with the `WithDistance` helper (now `WithProjection`). 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. The [reference](https://uql-orm.dev/querying/semantic-search.md) lists which engine has which.

## Why `$sort`?

Similarity search is sorting by distance, so UQL reuses `$sort`, which combines with `$where`, `$select`, `$limit` and ordinary sort fields:

```ts
const results = await pool.findMany(Article, {
  $where: { category: 'science' },
  $sort: {
    embedding: { $vector: queryVec, $distance: 'cosine' },
    title: 'asc',
  },
  $limit: 10,
});
```

## Get started

```bash
npm i uql-orm
```

- **[Full documentation](https://uql-orm.dev/querying/semantic-search.md)**
- **[Comparison](https://uql-orm.dev/comparison.md)**
- **[GitHub](https://github.com/rogerpadilla/uql)**

If something is broken or missing, open an issue on [GitHub](https://github.com/rogerpadilla/uql).

---

---

*[UQL](https://uql-orm.dev/index.md) is a JSON-native TypeScript ORM for Node.js and Bun. Supports PostgreSQL, PGlite, MySQL, MariaDB, MSSQL, SQLite, CockroachDB, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.*
