> 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

# CockroachDB

> Run UQL on CockroachDB over the Postgres wire protocol, and the differences that come with it.

Source: https://uql-orm.dev/cockroachdb

CockroachDB speaks the Postgres wire protocol, so UQL drives it with `pg` and shares the AST, quoting, JSONB, full-text and upsert logic with [PostgreSQL](https://uql-orm.dev/postgres.md). It is a separate dialect only because of the differences listed below.

```sh
npm install uql-orm pg
```

```ts
import { CrdbQuerierPool } from 'uql-orm/cockroachdb';

export const pool = new CrdbQuerierPool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
});
```

## Transactions retry

The default isolation is `serializable`, and contention surfaces as a retryable `40001`. Retry the whole `transaction` callback so the new attempt starts from a fresh snapshot:

```ts
const isRetryable = (err: unknown) =>
  typeof err === 'object' &&
  err !== null &&
  'code' in err &&
  err.code === '40001';
```

`read committed` is available on modern clusters and cuts most retries at the cost of the weaker guarantee:

```ts
await pool.transaction(run, { isolationLevel: 'read committed' });
```

## Primary keys

UQL’s generated surrogate key is `BIGINT GENERATED BY DEFAULT AS IDENTITY`. That works, but a monotonically increasing key concentrates every insert on one range. For a table under insert load, use a random UUID so writes spread:

```ts
import { Id } from 'uql-orm';

@Id({ type: 'uuid', onInsert: () => crypto.randomUUID() }) id?: string;
```

Random, not time-ordered: a UUIDv7 sorts by time and rebuilds the hotspot it was meant to avoid.

## Differences from Postgres

- **`created` on upserts** is always `undefined`: Postgres derives it from `xmax`, and CockroachDB’s transaction model has no equivalent system column, by design.

- **Vector search** is native, so no `CREATE EXTENSION vector`, and indexes use `CREATE VECTOR INDEX` with no access-method keyword. Three of pgvector’s four metrics work (`cosine`, `l2`, `inner`); `l1` is unimplemented server-side.

- **Index features** are narrower: expression and `INCLUDE` indexes work, `NULLS FIRST/LAST` and `jsonb_path_ops` do not.

- **[Full-text search](https://uql-orm.dev/querying/full-text.md)** reads the search as plain words: CockroachDB has no `WEBSEARCH_TO_TSQUERY`.

Everything else, native arrays, JSONB, `RETURNING` ids, [streaming](https://uql-orm.dev/querying/streaming.md) and [migrations](https://uql-orm.dev/migrations.md), behaves as on Postgres. Under Bun, [`bun:sql`](https://uql-orm.dev/bun-sql.md) reaches CockroachDB through its Postgres adapter while UQL keeps emitting CockroachDB SQL.
