TypeScript 7과 Project Corsa: Go로 다시 쓴 10배 빠른 컴파일러, 총정리
2025년 3월, Anders Hejlsberg가 카메라 앞에서 아무도 예상 못 한 말을 꺼냈어요.
"TypeScript 컴파일러를 Go로 포팅합니다."
Rust가 아니에요. 점진적 리팩토링도 아니고요. 컴파일러, 언어 서비스, 타입 체커 — TypeScript의 핵심 전부를 Go로 통째로 옮기겠다는 선언이에요. Microsoft는 이 프로젝트를 Project Corsa라 부르고, 지금 TypeScript 7.0으로 나오고 있어요.
숫자부터 볼까요. VS Code 코드베이스가 TypeScript 150만 줄이에요. 기존 tsc로 컴파일하면 약 78초. 새 Go 기반 컴파일러 tsgo로 돌리면? 7.5초. 2배도 아니고 10.4배 빨라진 거예요.
그냥 툴 하나 바뀌는 정도가 아니에요. TypeScript가 생긴 지 12년 만에 가장 큰 변화고, 빌드하고 배포하고 생각하는 방식 자체가 달라질 수 있어요. 하나씩 뜯어볼게요.
대체 왜 다시 쓰는 건가요?
Project Corsa를 이해하려면, 기존 컴파일러가 어디서 한계에 부딪혔는지부터 알아야 해요.
TypeScript 컴파일러는 원래 TypeScript 자체로 쓰였어요. 10년 넘게 잘 돌아갔는데, TypeScript가 웹 개발 대세가 되면서(2025년 8월에 GitHub에서 JavaScript를 처음 추월했어요) 자기 성공을 감당하기 힘들어진 거예요.
한계가 어디서 터졌나
-
대기업 코드베이스가 너무 커졌어요. Google, Microsoft, Stripe 같은 데서 TypeScript 수백만 줄을 돌리고 있거든요. 이 정도 규모면 IDE가 버벅거려요. 빨간 밑줄이 몇 초 늦게 뜨고, 자동 완성에 2-3초 걸리고, 프로젝트 전체 이름 바꾸기가 타임아웃 나요.
-
CI/CD가 발목을 잡았어요. 패키지 수백 개짜리 모노레포에서
tsc --build가 전체 파이프라인 중 가장 느린 단계인 경우가 많았어요. 타입 체크만 10분 넘는 경우도 있었고요. -
싱글 스레드의 한계. JavaScript 런타임은 태생적으로 싱글 스레드잖아요. 타입 체킹이든 파싱이든 추론이든 전부 코어 하나에서 순서대로 돌아가고, M4 Pro에 코어가 16개 있어도 나머지 15개는 놀고 있었다는 거예요.
왜 하필 Go인가요?
다들 이걸 궁금해하더라고요.
Rust는 왜 안 됐냐면, 성능은 최고겠지만 개발 속도가 문제예요. TypeScript 컴파일러 코드가 클로저를 많이 쓰고, 재귀 데이터 구조가 많고, 판별 유니온 패턴 매칭이 많은 함수형 스타일이거든요. Rust 소유권 모델이 이 스타일이랑 계속 충돌해요. 팀에서는 Rust로 쓰면 3-5배 더 오래 걸리고 아키텍처부터 뜯어고쳐야 한다고 봤어요.
결국 Go가 맞았던 이유:
-
코드 스타일이 딱 맞아요. TypeScript 컴파일러 코드가 사실 객체지향보다는 절차적·함수형에 가까워요. Go의 인터페이스, 일급 함수, 단순한 구조체가 기존 코드랑 잘 대응돼요.
-
고루틴 덕에 병렬 처리가 쉬워요. 스레드를 직접 관리할 필요 없이 고루틴으로 가볍게 병렬 처리할 수 있어요. 파일별 타입 체킹을 동시에 돌리기 딱이에요.
-
성능이 일정해요. Go GC가 저지연 앱에 최적화되어 있어서, V8 GC처럼 갑자기 멈추는 일이 없어요. IDE 반응성에 꼭 필요한 부분이에요.
-
바이너리 하나로 끝나요. Go 바이너리는 Node.js 없이 단독으로 돌아가요.
npm install필요 없이 받아서 바로 실행하면 돼요. -
팀이 빨리 적응했어요. Rust보다 Go를 훨씬 빨리 배우면서도 필요한 성능 향상은 다 달성할 수 있었대요.
기술적으로 뭐가 달라졌나요?
Project Corsa는 "같은 컴파일러가 그냥 빨라진 것"이 아니에요. 아키텍처 자체가 바뀌었어요.
아키텍처: 이전 vs 이후
TypeScript 5.x/6.x (JavaScript 기반):
소스 파일 → Scanner → Parser → Binder → Type Checker → Emitter
↑ ↓
싱글 스레드, 순차 파이프라인 .js + .d.ts
V8 위에서 Node.js로 실행
설치 크기 ~14MB (tsc + 런타임)
TypeScript 7.x (Go 기반):
소스 파일 → Scanner → Parser → Binder → Type Checker → Emitter
↑ ↑ ↑ ↓
병렬 병렬 파싱 멀티 스레드 .js + .d.ts
파일 I/O 타입 체킹
네이티브 바이너리, ~25MB 독립 실행
런타임 의존성 없음
뭐가 핵심이냐면요:
-
파일을 한꺼번에 읽어요. 고루틴으로 파일을 동시에 읽고 파싱해요. 수천 개 파일의 프로젝트에서 이것만으로도 2-3배 빨라져요.
-
타입 체킹도 병렬이에요. 가장 무거운 단계인 타입 체킹이 독립 모듈끼리 동시에 돌아가요. 서로 안 엮인 파일들은 한꺼번에 체크되니까, 10배 개선의 핵심이 여기 있어요.
-
메모리를 공유해요. JavaScript 워커 스레드는 데이터를 직렬화해서 넘겨야 하는데, Go 고루틴은 메모리를 그냥 같이 써요. 심볼 테이블 같은 걸 복사할 필요가 없어요.
-
데이터 구조가 더 효율적이에요. Go 네이티브 slice, map이 V8 힙 객체보다 메모리 관리가 깔끔해요. GC 부담이 줄고 캐시 효율도 올라가요.
tsgo CLI
새 컴파일러는 tsgo라는 이름으로 나오고, 기존 tsc랑 같이 쓸 수 있어요:
# 기존 TypeScript 컴파일러 (TS 6.x, 여전히 돌아감) npx tsc --build # 새 Go 기반 컴파일러 npx tsgo --build # 독립 바이너리로 직접 (Node.js 없이) tsgo --build
tsgo는 tsconfig.json을 그대로 받고 출력도 같아요. tsc로 되는 코드면 tsgo로도 되고, 나오는 JS랑 .d.ts도 동일해야 돼요.
TypeScript 6.0이 다리 역할
TypeScript 6.0은 JavaScript 시대에서 Go 시대로 넘어가는 징검다리에요:
타임라인:
TS 5.9 (2025년 말) → 마지막 "일반" 릴리스
TS 6.0 (2026년 2월) → 징검다리: deprecated 처리 + 준비
TS 7.0 (2026년 중반) → Go 기반 컴파일러 (Project Corsa)
TS 7.0 대비해서 TS 6.0에서 바뀌는 것들:
target: "es5"deprecated. TS 7에서 ES5 출력 안 돼요. 필요하면 Babel이나 SWC를 따로 붙이세요.- 레거시 모듈 해석 deprecated.
"moduleResolution": "node"(구버전)이랑"classic"못 써요."node16","nodenext","bundler"쓰세요. - 기본값이 바뀌어요. 기본
target이"es2025", 기본module이"nodenext"로. - Temporal API 타입 추가. JavaScript Temporal API 타입이 기본 포함.
10배가 진짜예요?
"10배 빠르다"는 소리만 들으면 과장 같잖아요. 맥락을 좀 붙여볼게요.
풀 빌드
| 코드베이스 | TS 라인 수 | tsc (TS 6.x) | tsgo (TS 7.x) | 몇 배? |
|---|---|---|---|---|
| VS Code | 150만 | ~78초 | ~7.5초 | 10.4x |
| Playwright | ~80만 | ~45초 | ~3.5초 | 12.9x |
| TypeORM | ~35만 | ~28초 | ~2.8초 | 10x |
| 중간 규모 (5만 줄) | 5만 | ~4초 | ~0.8초 | 5x |
| 작은 앱 (5천 줄) | 5천 | ~1.2초 | ~0.5초 | 2.4x |
보이죠? 프로젝트가 클수록 효과가 커요. 파일이 많으면 병렬 처리를 그만큼 더 쓸 수 있으니까요. 파일 20개짜리 사이드 프로젝트에서는 체감이 크지 않아요.
IDE 체감 (Language Service)
사실 대부분 개발자한테는 이게 더 와닿을 거예요:
500개 파일짜리 TypeScript 프로젝트를 열었을 때
TS 6.x 기준:
프로젝트 로딩: 4-6초
첫 자동 완성까지: 2-3초
정의로 이동: 500ms-1초
타입 호버: 200-500ms
전체 이름 바꾸기: 5-15초
TS 7.x (tsgo) 기준:
프로젝트 로딩: 0.5-1초
첫 자동 완성까지: 200-400ms
정의로 이동: 50-150ms
타입 호버: 30-100ms
전체 이름 바꾸기: 1-3초
빌드 속도보다 이쪽이 체감 효과가 더 클 수 있어요. IntelliSense가 빨라지면 기다리는 시간이 줄고, 흐름이 안 끊기고, 코딩 자체가 더 매끄러워지거든요.
메모리도 줄었어요
VS Code 코드베이스 타입 체킹 기준
TS 6.x (Node.js):
최대 메모리: ~4.2 GB
평균: ~3.1 GB
TS 7.x (tsgo):
최대 메모리: ~1.8 GB
평균: ~1.2 GB
줄어든 양: 약 57%
CI 러너에 RAM이 적어도 되고, 노트북에서 스와핑 없이 개발할 수 있고, Docker 메모리 제한도 더 타이트하게 잡을 수 있어요.
뭐가 깨지나요?
TypeScript 7은 동작 호환을 목표로 하고 있지만, "목표"랑 "실제"는 다를 수 있어요.
🔴 고위험: Compiler API 플러그인
TypeScript Compiler API(ts.createProgram, ts.transform 등)를 쓰고 있다면 가장 조심해야 해요. Go 기반 컴파일러는 API가 달라서, 기존 JavaScript Compiler API로 만든 커스텀 트랜스포머가 tsgo에서는 안 돌아가요.
// ❌ tsgo에서 안 되는 코드 import * as ts from 'typescript'; const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => { return (sourceFile) => { return ts.visitEachChild(sourceFile, visitor, context); }; };
영향받는 대표 도구:
ts-morph(코드 조작)ttypescript(커스텀 트랜스포머 로더)ts.LanguageServicePlugin계열 전부- Compiler API를 깊게 쓰는 빌드 도구
TS 7에서 gRPC/IPC 기반의 새 크로스 랭귀지 API가 나올 예정이지만, 기존 플러그인은 재작성해야 해요.
🟡 중위험: Strict가 기본 ON
TypeScript 7부터는 strict: true가 기본이에요. tsconfig에 명시 안 했으면 아래가 전부 켜져요:
{ "compilerOptions": { "strict": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictBindCallApply": true, "strictPropertyInitialization": true, "noImplicitAny": true, "noImplicitThis": true, "alwaysStrict": true, "useUnknownInCatchVariables": true } }
strict를 안 쓰던 코드베이스라면 업그레이드하는 순간 에러가 수백~수천 개 쏟아져요. 지금 상태 유지하려면 "strict": false를 직접 넣으세요.
🟢 저위험: 출력 미세 차이
tsgo가 내놓는 JS는 tsc랑 기능적으로 같지만, 공백이나 소스맵 컬럼 번호에 미세한 차이가 있을 수 있어요. 대부분 프로젝트에선 눈에 안 보여요. 출력 JS를 글자 단위로 비교하는 스냅샷 테스트가 있다면 깨질 수 있는데, 스냅샷 업데이트하면 끝이에요.
지금부터 준비하는 법
TS 7 정식 나올 때까지 기다릴 필요 없어요.
1. tsconfig.json 점검
npx tsgo --build --noEmit 2>&1 | grep -i "deprecated"
직접 확인할 것:
target: "es5"→"es2020"이상moduleResolution: "node"→"node16"또는"bundler"module: "commonjs"→"node16"또는"nodenext"검토
2. Strict 모드 켜보기
npx tsc --strict --noEmit 2>&1 | wc -l
에러가 감당할 만하면 지금 켜세요. 수천 개면 하나씩 점진적으로:
{ "compilerOptions": { "strictNullChecks": true, "noImplicitAny": true, "strictFunctionTypes": true } }
3. Compiler API 의존성 확인
grep -r "from 'typescript'" node_modules/*/src/ 2>/dev/null | head -20
빌드 툴이나 린트 플러그인 중에 Compiler API를 깊이 쓰는 게 있는지 확인해두세요.
4. tsgo로 미리 돌려보기
npm install -D [email protected] npx tsgo --noEmit # 속도 비교 time npx tsc --noEmit time npx tsgo --noEmit
생태계는 어떻게 되나요?
번들러·빌드 도구
Vite / Rolldown / esbuild / SWC: 트랜스파일은 자체적으로 하고 타입 체크만 tsc에 맡기는 구조라 코어 기능에는 영향 없어요. CI에서 tsgo로 바꿔 타입 체크를 더 빠르게 할 수 있어요.
webpack (ts-loader): Compiler API를 직접 쓰고 있어서 tsgo 호환 업데이트가 필요해요.
IDE
VS Code: Go 기반 언어 서비스를 도입할 예정이에요. 큰 프로젝트에서 IntelliSense가 확 빨라질 거예요. VS Code 팀이 이미 VS Code 자체 코드베이스에서 tsgo를 쓰고 있어요.
프레임워크
Next.js / Nuxt / Remix / SvelteKit: 빌드할 때 타입 체크에 tsc를 쓰니까, tsgo로 바꾸면 코드 수정 없이 바로 빨라져요.
Angular: ngc가 Compiler API를 광범위하게 써서 마이그레이션이 가장 복잡한 축에 들어요. Angular 팀이 작업 중이에요.
"TypeScript가 TypeScript로 안 쓰였는데 그래도 TypeScript야?"
발표 직후에 이런 논쟁이 꽤 있었어요. Self-hosting이 깨졌다는 의견도 있었고, JavaScript 개발자를 위한 언어의 핵심이 Go라니 아이러니하다는 반응도 있었고요.
현실적으로 보면요: TypeScript라는 언어 자체는 하나도 안 변해요. .ts 파일, 타입 어노테이션, tsconfig.json — 전부 그대로. 컴파일러는 구현 방법일 뿐이에요. Python으로 가장 많이 쓰는 구현체가 C로 쓴 CPython인 것처럼, TypeScript도 더 빠른 언어로 만든 컴파일러를 쓰게 되는 거예요.
솔직히 78초가 7.5초로 줄어드는 걸 직접 보니까 논쟁이 금방 사그라들던데요.
더 넓게 보면: JS 툴링의 "네이티브 전환" 흐름
TypeScript 7은 단독 사건이 아니에요. JavaScript 툴링 전체가 이 방향으로 가고 있어요:
| 도구 | 원래 언어 | 뭘로 바꿨나 | 몇 배? |
|---|---|---|---|
| TypeScript 7 (tsgo) | TypeScript | Go | 10x |
| Rolldown (Rollup 대체) | JavaScript | Rust | 10-15x |
| esbuild | — | Go | 100x vs webpack |
| SWC (Babel 대체) | JavaScript | Rust | 20x |
| Biome (ESLint+Prettier 대체) | JavaScript | Rust | 25x |
| Oxc (파서/린터) | JavaScript | Rust | 50x |
패턴이 보이죠? 성능이 중요한 인프라는 시스템 언어로 옮기고, 개발자가 쓰는 API는 JavaScript/TypeScript로 유지하는 거예요. 코딩할 때 달라지는 건 없는데 밑단이 네이티브로 바뀌는 거예요.
JavaScript가 죽는 게 아니에요. 역할이 분화되고 있는 거예요. 앱 로직, UI, 비즈니스 규칙은 JavaScript/TypeScript가 하고, 컴파일·린팅·번들링은 멀티코어와 효율적인 메모리를 쓸 수 있는 도구한테 맡기는 구조요.
앞으로 일정
단기 (2026년 Q1-Q2)
- TypeScript 7.0 베타 사용 가능
tsgoCLI npm 설치 가능- 주요 번들러·프레임워크
tsgo통합 시작
중기 (2026년 Q3-Q4)
- TypeScript 7.0 안정판 출시
- VS Code가 Go 기반 언어 서비스를 기본으로 전환
- 플러그인 생태계 새 API로 이동
장기 (2027년~)
- TypeScript 6.x (
tsc) 유지보수 모드 - 새 기능은 Go에서 먼저 구현
- JS 기반 컴파일러에서는 불가능했던 것들 (패키지 경계 넘는 전체 프로그램 분석 같은) 가능
정리하면
TypeScript 7과 Project Corsa는 TypeScript가 생긴 이래 가장 큰 변화예요. Self-hosted JavaScript 컴파일러에서 Go 네이티브 바이너리로의 전환은 단순히 빨라지는 게 아니라, 새로운 가능성이 열리는 아키텍처 전환이에요.
대부분 개발자한테는 가장 좋은 의미로 별거 아닌 업그레이드가 될 거예요. 코드 그대로, tsconfig 그대로, 그런데 전부 빨라져요. 훨씬.
도구 만드는 분들이나 프레임워크 개발자한테는 진짜 마이그레이션 작업이 필요해요. Compiler API 변경이 핵심인데, 지금부터 tsgo --noEmit로 한번 돌려보세요.
78초짜리 빌드가 7.5초로 줄었는데 안 웃으면, 뭘 봐야 웃을 수 있는 거예요? 😄
관련 도구 둘러보기
Pockit의 무료 개발자 도구를 사용해 보세요