TypeORM — 도메인 홈
이 도메인이 답하는 질문: “TypeScript에서 SQL을 객체처럼 다루고 싶을 때, TypeORM은 어떻게 동작하며 — 왜 Prisma·Drizzle이 그 자리를 위협하고 있는가?” 한 줄 답 (Pyramid Top): “TypeORM은 데코레이터로 클래스에 메타데이터를 박아 컴파일 타임 타입과 런타임 메타데이터를 동시에 얻는 DataMapper ORM이다 — 그 한 줄 트릭이 매력의 전부이자 한계의 출발점이다.”
도메인 지도 (5-레이어)
어떤 챕터가 들어 있나
| # | 챕터 | 한 줄 답 | 핵심 키워드 |
|---|---|---|---|
| 00 | 기초 | TypeORM은 데코레이터로 ORM 메타데이터를 박는 DataMapper다. | decorator · reflect-metadata · ActiveRecord vs DataMapper · 역사 |
| 01 | Entity & 데코레이터 | 클래스 한 개 + 데코레이터 = 테이블 정의 + 런타임 메타. | @Entity · @Column · @PrimaryGeneratedColumn · embedded · STI |
| 02 | Relations | 관계는 데코레이터 + 외래키 선언 + 로딩 전략의 3축으로 결정된다. | OneToOne · OneToMany · ManyToMany · JoinColumn · eager/lazy |
| 03 | Repository & DataMapper | Repository는 엔티티를 모르는 도메인 코드와 영속성을 분리하는 경계다. | Repository · DataMapper vs ActiveRecord · find · save · cascade |
| 04 | QueryBuilder | find가 답이 안 될 때 QueryBuilder가 SQL을 다시 주는 탈출구다. | createQueryBuilder · join · subquery · raw · select |
| 05 | Transaction & DataSource | DataSource는 연결의 인생 전체고, Transaction은 그 인생의 한 챕터다. | DataSource · QueryRunner · transaction · isolation · pool |
| 06 | Migration & Schema | synchronize: true는 개발용 폭탄이다 — 프로덕션은 generate된 migration만 믿어라. | synchronize · migration:generate · migration:run · revert |
| 07 | 성능 & N+1 | TypeORM의 거의 모든 성능 문제는 eager + 깊은 관계 + find 조합이다. | N+1 · loadRelationIds · cache · relations · join vs subquery |
| 08 | 이론 & 대안 | Prisma는 스키마 우선, Drizzle은 SQL 우선, TypeORM은 클래스 우선. | Prisma · Drizzle · Kysely · MikroORM · Sequelize · 비교 매트릭스 |
| 09 | 실전 사례 | NestJS 진영의 사실상 표준 — 하지만 Prisma로 갈아타는 팀이 많아진 이유. | NestJS @nestjs/typeorm · multi-tenant · 사가 패턴 · 마이그레이션 사례 |
| ★ | 용어 사전 | 100+ 용어 사전. | 데코레이터 · 메타데이터 · QueryRunner · subscriber · STI |
Why — 왜 TypeORM 도메인을 한 묶음으로 보는가
세 가지 잘못된 직관이 거의 모든 TypeORM 사고의 출처다.
| 잘못된 직관 | 실제 | 어디서 다루나 |
|---|---|---|
| ”TypeORM은 클래스만 짜면 알아서 다 한다” | 데코레이터로 메타데이터를 직접 박는 일이고, 그 메타가 SQL을 만든다. | 00, 01 |
| ”ActiveRecord와 DataMapper는 취향 차이다” | DataMapper는 도메인 객체가 영속성을 모르게 만드는 설계 원칙이다 — 큰 코드베이스에서 의미가 갈린다. | 03 |
| ”synchronize: true는 편하다” | 프로덕션 데이터의 비가역적 삭제를 부른다. 개발용 토글이다. | 06 |
이 도메인을 5-레이어로 보면 — Entity가 메타를 박고, Repository가 그것을 SQL로 번역하며, Transaction이 일관성을 보장하고, Migration이 스키마를 진화시키며, Performance가 그 위의 운영 비용을 줄인다.
How — 어떻게 읽나
- 처음 TypeORM을 만나는 사람: 00 → 01 → 02 → 03 순서. 3시간이면 CRUD 가능한 멘탈모델이 잡힌다.
- 이미 쓰고 있는데 N+1로 고통받는 사람: 07만 봐도 된다. 그 다음 04(QueryBuilder)로.
- 프로덕션 배포를 앞둔 사람: 05(트랜잭션) → 06(마이그레이션) → 09(NestJS 사례) 필수.
- 다른 ORM으로 갈아탈지 고민하는 사람: 00 → 08(대안 비교) → 09(사례). 결정 시간 1시간.
What — 도메인 한 페이지 요약
| 챕터 | 한 줄 결론 |
|---|---|
| 00 | TypeORM은 데코레이터 + reflect-metadata에 모든 것을 거는 DataMapper ORM이다 — 그 한 줄 결정이 매력과 한계 모두를 만든다. |
| 01 | @Entity와 @Column은 런타임에 존재하는 메타데이터고, TypeORM은 그 메타로 DDL과 SQL을 동시에 생성한다. |
| 02 | 관계는 데코레이터 두 개(예: @OneToMany/@ManyToOne)와 JoinColumn 위치와 로딩 전략 세 가지가 동시에 맞아야 동작한다. |
| 03 | Repository<Entity>는 제네릭 게이트웨이다 — DataMapper의 원칙은 “엔티티가 자기 save를 호출하지 않는다”. |
| 04 | QueryBuilder는 SQL 추상의 손잡이를 다시 손에 쥐는 길이다 — find가 풀 수 없는 join·서브쿼리·raw가 여기 있다. |
| 05 | DataSource는 연결의 정체성이고, Transaction은 그 연결 위의 임시 약속이다 — QueryRunner로 명시할 때만 안전하다. |
| 06 | synchronize는 개발용 자동 폭탄이다 — 프로덕션은 generate된 SQL을 사람이 읽고 commit한 migration만 신뢰한다. |
| 07 | N+1은 TypeORM의 기본값이다 — relations/leftJoinAndSelect/loadRelationCountAndMap을 의식적으로 써야 사라진다. |
| 08 | Prisma는 스키마 → 클라이언트 코드젠, Drizzle은 SQL DSL, TypeORM은 데코레이터. 셋은 다른 트레이드오프를 산다. |
| 09 | NestJS에서 TypeORM은 기본 선택지였지만, 마이그레이션·타입 정확도·성능 이유로 Prisma·Drizzle로의 이주가 흔하다. |
What-if — 이 도메인을 단편적으로만 알면
- Entity만 알고 Relations를 모르면: 관계 한쪽만 정의해 지속적인 update가 풀리지 않는 버그를 만든다.
- Repository만 알고 QueryBuilder를 모르면:
find옵션을 모든 곳에 욱여넣어 가독성 0의 거대한 객체를 만든다. - Transaction만 알고 Migration을 모르면: 새 컬럼 추가 → 운영 중 다운타임 → 트랜잭션이 반쯤 보이는 컬럼을 만난다.
- Migration만 알고 Performance를 모르면: 잘 만든 스키마가 런타임에 N+1로 죽는다 — eager 한 줄이 원인.
Insight — 한 단락 이야기
“TypeORM은 2016년, TypeScript의 데코레이터 제안서가 살아 있을 때 태어났다”
Umed Khudoiberdiev가 2016년 시작한 TypeORM은 TC39의 Stage 1 데코레이터 + experimentalDecorators 플래그에 모든 것을 걸었다. 같은 해 Angular 2가 데코레이터를 정착시키고 있었고, NestJS가 Angular 스타일을 백엔드로 들고 오면서 — 데코레이터 ORM은 TypeScript 진영의 사실상 표준이 되었다. 하지만 2019년 즈음 Prisma가 코드젠으로 데코레이터를 우회하는 길을 보이고, 2023년 Drizzle이 SQL DSL로 또 다른 길을 열었다. TypeORM의 매력은 데코레이터 한 줄이지만, 데코레이터 spec이 9년째 Stage 2-3을 떠도는 이상 — TypeORM의 운명도 그 spec의 운명과 묶여 있다. 이 도메인이 하는 일은 그 매력과 한계의 지렛대가 어디에 있는지를 다섯 층으로 분해하는 것.
Mermaid 4색 규약
이 도메인의 모든 다이어그램은 다음 색을 따른다.
색은 역할이고 모양은 의미다 — 다른 도메인과도 일관된다.
한 단락 요약
TypeORM은 데코레이터로 클래스를 테이블로 만드는 DataMapper ORM이다. 그 위에 Entity(메타 박기) · Repository(SQL 번역) · Transaction(일관성) · Migration(스키마 진화) · Performance(N+1 흡수) 다섯 층이 쌓여 있다. 이 도메인을 끝내면 “TypeORM을 써야 하나?” 대신 “내 팀은 어느 레이어에서 가장 자주 다치는가, 그 자리에 TypeORM이 가장 적합한 도구인가” 라는 질문을 던지게 된다.