Files
2nd/10_Wiki/Topics/Domain_Programming/Coding/DB_ORM_Comparison.md
T
Antigravity Agent c24165b8bc refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게
[공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류.
문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인).

- Topic_Programming → Domain_Programming (내부 구조 보존)
- Topic_Graphic → Domain_Design
- Topic_Business → Domain_Product
- Topic_General → Domain_General
- _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning),
  Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing)
- 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서)
- 빈 폴더 정리 (memory/procedures)
- 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:05:56 +09:00

5.6 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
db-orm-comparison ORM 비교 — Prisma / Drizzle / Kysely / TypeORM Coding draft B conceptual 2026-05-09 2026-05-09
database
orm
prisma
drizzle
kysely
vibe-coding
language applicable_to
TS
Backend
Prisma
Drizzle
Kysely
TypeORM
Sequelize
MikroORM
query builder

ORM 비교

Prisma = 강 type 안전 + DX, Drizzle = 가볍고 SQL 그대로, Kysely = pure query builder, TypeORM = 옛 ActiveRecord. 추천 = Drizzle (modern) 또는 Prisma (DX).

📖 핵심 개념

  • ORM: object 매핑.
  • Query builder: SQL 같은 chained API.
  • Type-safe: schema → type infer.
  • Migration: schema 변경 자동 SQL.

💻 코드 패턴

Prisma

// schema.prisma
model User {
  id    String  @id @default(uuid())
  email String  @unique
  posts Post[]
}

model Post {
  id     String @id @default(uuid())
  title  String
  userId String
  user   User   @relation(fields: [userId], references: [id])
}
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

const u = await prisma.user.findUnique({
  where: { id },
  include: { posts: true },
});

await prisma.user.create({
  data: { email, posts: { create: [{ title: 'first' }] } },
});

await prisma.user.update({
  where: { id }, data: { email: newEmail },
});

→ Pros: 강 type, migration 자동. Cons: query engine binary, 일부 제약.

Drizzle (modern, SQL-style)

import { pgTable, uuid, text, integer } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  email: text('email').unique().notNull(),
});

export const posts = pgTable('posts', {
  id: uuid('id').primaryKey().defaultRandom(),
  title: text('title').notNull(),
  userId: uuid('user_id').references(() => users.id),
});
import { drizzle } from 'drizzle-orm/node-postgres';
import { eq } from 'drizzle-orm';

const db = drizzle(pool);

const result = await db.select().from(users).where(eq(users.id, id));

await db.insert(users).values({ email });

await db.update(users).set({ email: newEmail }).where(eq(users.id, id));

// Joined
const result = await db
  .select()
  .from(users)
  .leftJoin(posts, eq(users.id, posts.userId))
  .where(eq(users.id, id));

→ Pros: 가볍고 빠름, SQL 그대로. Cons: 약간 verbose.

Kysely (pure query builder)

import { Kysely, PostgresDialect } from 'kysely';

interface DB {
  users: { id: string; email: string };
  posts: { id: string; title: string; user_id: string };
}

const db = new Kysely<DB>({ dialect: new PostgresDialect({ pool }) });

const u = await db.selectFrom('users').where('id', '=', id).selectAll().executeTakeFirst();

await db.insertInto('users').values({ id: uuid(), email }).execute();

const joined = await db
  .selectFrom('users')
  .leftJoin('posts', 'posts.user_id', 'users.id')
  .where('users.id', '=', id)
  .selectAll()
  .execute();

→ Pros: SQL 정확 매핑, 매우 typed. Cons: schema 직접 정의.

TypeORM (옛, ActiveRecord)

@Entity()
class User {
  @PrimaryGeneratedColumn('uuid') id!: string;
  @Column({ unique: true }) email!: string;
  @OneToMany(() => Post, p => p.user) posts!: Post[];
}

const u = await User.findOne({ where: { id }, relations: ['posts'] });

→ 옛 design, 새 프로젝트 권장 X.

Migration 비교

# Prisma
prisma migrate dev --name add_user_email
prisma migrate deploy

# Drizzle
drizzle-kit generate
drizzle-kit migrate

# Kysely
# 직접 SQL 파일 + kysely-codegen 으로 type

Transaction

// Prisma
await prisma.$transaction(async (tx) => {
  await tx.user.create({...});
  await tx.post.create({...});
});

// Drizzle
await db.transaction(async (tx) => {
  await tx.insert(users).values(...);
});

// Kysely
await db.transaction().execute(async (tx) => {
  await tx.insertInto('users').values(...).execute();
});

Raw SQL (escape hatch)

// Prisma
const result = await prisma.$queryRaw<User[]>`SELECT * FROM users WHERE name LIKE ${pattern}`;

// Drizzle
import { sql } from 'drizzle-orm';
const r = await db.execute(sql`SELECT * FROM users WHERE name LIKE ${pattern}`);

// Kysely
const r = await sql<User[]>`SELECT * FROM users WHERE name LIKE ${pattern}`.execute(db);

Connection pool

// 모두 공통: pg / mysql 의 Pool wrap
import { Pool } from 'pg';
const pool = new Pool({ connectionString, max: 20 });

Edge runtime

Drizzle: HTTP driver (Neon / PlanetScale) 가벼움. Edge OK.
Prisma: Accelerate / Data Proxy 필요. 기본은 binary (Edge X).
Kysely: HTTP driver 호환.

🤔 의사결정 기준

상황 추천
빠른 시작 + DX Prisma
Edge runtime Drizzle / Kysely
가벼운 + SQL 명확 Drizzle
Pure query builder Kysely
매우 작은 bundle Drizzle
큰 schema + relation 복잡 Prisma 또는 Drizzle
옛 시스템 유지 TypeORM

안티패턴

  • N+1 ORM: include 안 쓰고 loop 안 쿼리. Prisma include / Drizzle leftJoin.
  • 모든 column SELECT: select 명시.
  • Connection pool 매번 새로: lazy singleton.
  • Migration 수동 prod: drift. CI 에서 auto.
  • Transaction 안 외부 API: 롤백 시 부수효과만 남음.
  • Raw SQL string concat: SQL injection. parameterized.
  • Schema 두 곳 (.prisma + ts type): drift. infer.

🤖 LLM 활용 힌트

  • 새 프로젝트 = Drizzle 또는 Prisma.
  • Edge / serverless = Drizzle (Neon HTTP).
  • Prisma = DX 우월하지만 binary.

🔗 관련 문서