Databases
ORMs
Prisma, Drizzle, TypeORM, and the Active Record vs Data Mapper debate.
Object-Relational Mappers (ORMs)
SQL is powerful, but mapping rows to Objects/Types manually is tedious. ORMs automate this.
The Spectrum
1. Active Record (Rails, Eloquent, TypeORM)
The Model is the Database Row. It has methods to save itself.
const user = new User();
user.name = "Alice";
user.save(); // The object knows how to connect to DB- Pros: Fast development, intuitive.
- Cons: Violates Single Responsibility Principle. Mixing Logic and Persistence. Hard to test.
2. Data Mapper (Hibernate, MikroORM)
The Model is a dumb class. A separate "Repository" or "Manager" handles saving.
const user = new User("Alice");
repo.save(user);- Pros: Pure domain objects. Clean architecture friendly.
- Cons: More boilerplate.
3. The Modern Query Builder (Prisma, Drizzle)
Not strictly an ORM, but a type-safe layer over SQL.
- Prisma: Generates a massive TypeScript client based on
schema.prisma. Heavy runtime. - Drizzle: "If you know SQL, you know Drizzle." Lightweight, almost zero runtime overhead.
The Danger Zone
The N+1 Problem
ORMs make it easy to accidentally DDOS your database.
const users = await User.find(); // 1 Query
users.forEach(u => {
console.log(u.posts); // Hidden Query per user!
});Fix: Eager Loading. User.find({ include: { posts: true } }).
Leaky Abstractions
ORMs try to hide SQL, but they fail for complex queries.
- Eventually, you will need to write raw SQL (
prisma.$queryRaw). - If you rely 100% on the ORM, you will write inefficient queries because you don't understand what the ORM is generating under the hood.
Opinion
Drizzle ORM is currently the sweet spot for TypeScript backends. It gives you type safety and migrations without hiding the SQL reality from you.