Raw SQL gives you control but no type safety. TypeORM uses decorators and class inheritance. Knex.js is a query builder without schema management. You want to define your schema once and get types, queries, and migrations automatically.
That's Prisma — the TypeScript ORM that generates a fully typed client from your schema.
Quick Start
npm install prisma @prisma/client
npx prisma init
Schema Definition
// prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(cuid())
email String @unique
name String?
posts Post[]
profile Profile?
createdAt DateTime @default(now())
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String
tags Tag[]
createdAt DateTime @default(now())
}
model Profile {
id String @id @default(cuid())
bio String?
user User @relation(fields: [userId], references: [id])
userId String @unique
}
model Tag {
id String @id @default(cuid())
name String @unique
posts Post[]
}
npx prisma migrate dev --name init # Creates tables + generates client
Type-Safe Queries
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
// Find with relations
const user = await prisma.user.findUnique({
where: { email: "dev@example.com" },
include: { posts: true, profile: true },
});
// user.posts is typed as Post[] — autocomplete works!
// Create with nested relations
const newUser = await prisma.user.create({
data: {
email: "new@example.com",
name: "Aleksej",
profile: { create: { bio: "Developer" } },
posts: {
create: [
{ title: "First Post", content: "Hello!" },
{ title: "Second Post", published: true },
],
},
},
include: { posts: true, profile: true },
});
// Complex filtering
const publishedPosts = await prisma.post.findMany({
where: {
published: true,
author: { email: { endsWith: "@gmail.com" } },
tags: { some: { name: "typescript" } },
},
orderBy: { createdAt: "desc" },
take: 20,
select: { id: true, title: true, author: { select: { name: true } } },
});
// Aggregation
const stats = await prisma.post.aggregate({
_count: true,
_avg: { views: true },
where: { published: true },
});
// Transaction
const [deletedPosts, deletedUser] = await prisma.$transaction([
prisma.post.deleteMany({ where: { authorId: userId } }),
prisma.user.delete({ where: { id: userId } }),
]);
Prisma Studio — Visual Database Browser
npx prisma studio
# Opens browser at localhost:5555 — browse/edit data visually
Prisma vs Drizzle vs TypeORM vs Kysely
| Feature | Prisma | Drizzle | TypeORM | Kysely |
|---|---|---|---|---|
| Approach | Schema-first ORM | Code-first ORM | Decorator ORM | Query builder |
| Type safety | Generated client | Inferred | Decorators | Manual schema |
| Migrations | Built-in (auto) | Built-in | Built-in | Via plugin |
| Raw SQL control | Limited | High | Medium | Full |
| Bundle size | Heavy (~7MB) | Light (~50KB) | Medium (~2MB) | Light (~30KB) |
| Studio/GUI | Prisma Studio | Drizzle Studio | None | None |
Choose Prisma for rapid development, auto-generated types, and Prisma Studio.
Choose Drizzle/Kysely for smaller bundles and more SQL control.
Start here: prisma.io
Need custom data extraction, scraping, or automation? I build tools that collect and process data at scale — 78 actors on Apify Store and 265+ open-source repos. Email me: Spinov001@gmail.com | My Apify Actors
Top comments (0)