> 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

# ORM Type Safety Comparison

> Ordinary mistakes written in six TypeScript ORMs, compiled live: Drizzle vs MikroORM vs Prisma vs Sequelize vs TypeORM vs UQL.

Source: https://uql-orm.dev/type-safety

The same ordinary mistakes, written in six ORMs’ own APIs against the same two entities: a misspelled key, a text operator on a number, a sum over a text column, a read of a column you never selected, and eight more. The editor runs the real TypeScript compiler over the real packages. Switch tabs to see what each one catches.

```ts
import { asc, eq, gt, like, sum } from 'drizzle-orm';
import { drizzleUsers } from '../src/schema';
import { clients } from './clients';

const { drizzleDb: db } = clients;

// Misspelled column in the projection | emial -> email
await db
  .select({ id: drizzleUsers.id, email: drizzleUsers.emial })
  .from(drizzleUsers);

// Misspelled column in the filter | createdat -> createdAt
await db
  .select({ id: drizzleUsers.id })
  .from(drizzleUsers)
  .where(gt(drizzleUsers.createdat, 0));

// String value against a numeric column | 'one' -> 1
await db
  .select({ id: drizzleUsers.id })
  .from(drizzleUsers)
  .where(eq(drizzleUsers.createdAt, 'one'));

// Text operator against a numeric column | like(drizzleUsers.createdAt, 'abc') -> gt(drizzleUsers.createdAt, 1)
await db
  .select({ id: drizzleUsers.id })
  .from(drizzleUsers)
  .where(like(drizzleUsers.createdAt, 'abc'));

// Misspelled column in the sort | idd -> id
await db
  .select({ id: drizzleUsers.id })
  .from(drizzleUsers)
  .orderBy(asc(drizzleUsers.idd));

// Sum over a text column | name -> id
await db.select({ total: sum(drizzleUsers.name) }).from(drizzleUsers);

// Misspelled column inside a loaded relation | nmae -> name
await db.query.Company.findMany({
  columns: { id: true },
  with: { users: { columns: { nmae: true } } },
});

// Misspelled column in inserted data | emails -> email
await db
  .insert(drizzleUsers)
  .values([{ name: 'New User', emails: 'new@example.com' }]);

// Required column left out of inserted data | 'New User' } -> 'New User', email: 'new@example.com' }
await db.insert(drizzleUsers).values([{ name: 'New User' }]);

// Number written into a text column | 42 -> 'Updated Name'
await db.update(drizzleUsers).set({ name: 42 }).where(eq(drizzleUsers.id, 1));

// Reading a column the projection left out | user.email -> user.name
const [user] = await db
  .select({ id: drizzleUsers.id, name: drizzleUsers.name })
  .from(drizzleUsers);
export const unselected = user.email;

// Reading a misspelled column off a loaded relation | .nmae -> .name
const [company] = await db.query.Company.findMany({
  columns: { id: true },
  with: { users: { columns: { id: true, name: true } } },
});
export const nested = company.users[0].nmae;
```

type-safety/drizzle.ts · static preview

## How it is scored

The files come unchanged from [ts-orm-benchmark](https://github.com/rogerpadilla/ts-orm-benchmark), which also runs the [speed benchmark](https://uql-orm.dev/benchmark.md). Each ORM’s file compiles twice: as written, and with every mistake fixed. A mistake counts as caught only when it errors and the fixed version compiles clean.

The benchmark scores with TypeScript 7.0.2. This site recompiles the same files at build time with TypeScript 6.0.3, the compiler the editor runs too, and the deploy fails if a verdict changes.

Each entry uses the API its main package offers. MikroORM’s entities use `defineEntity`, since its decorators moved to `@mikro-orm/decorators`. TypeORM’s decorators are the legacy kind, so its entities use `EntitySchema`, which scores the same. Drizzle’s flat probes use `db.select()` and its relation probes `db.query.*`, the same code its benchmark times.

## Reading the result

UQL catches all twelve, Prisma eleven, Drizzle, MikroORM and TypeORM ten, and Sequelize six. A one-probe gap should not decide a tool on its own, and this page says nothing about migrations, error readability or type-checking speed on large schemas.

I wrote UQL, so weigh the verdict accordingly. The [method](https://github.com/rogerpadilla/ts-orm-benchmark#type-safety) is open, and every entry faces the same probes.

[Rename Safety](https://uql-orm.dev/rename-safety.md)Six ORMs renaming a field, a foreign key and a relation: which indexes, checks, relations, queries and raw SQL follow.

[Benchmark](https://uql-orm.dev/benchmark.md)The other half: what each ORM costs on a full PostgreSQL round trip, on Bun and Node.

[Comparison](https://uql-orm.dev/comparison.md)Drizzle vs MikroORM vs Prisma vs TypeORM vs UQL, with actual code for every common operation.

---

## Try it

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

Entities are plain classes and queries are plain JSON: nothing to generate, and no schema file to keep in sync.

[Quick Start](https://uql-orm.dev/getting-started.md) [GitHub](https://github.com/rogerpadilla/uql)

---
