TypeScript가 Go로 갈아탄 진짜 이유 (tsc 10배 속도 향상의 비밀)
(Updated: )
General

TypeScript가 Go로 갈아탄 진짜 이유 (tsc 10배 속도 향상의 비밀)


📌 3줄 요약
  • TypeScript 팀이 컴파일러(tsc)를 Go로 재작성하는 Project Corsa를 공식 발표했습니다. TypeScript 7.0에서 반영 예정.
  • Rust 대신 Go를 선택한 이유는 GC 지원으로 기존 코드 포팅이 쉽고, Goroutine으로 AST 병렬 순회가 가능하기 때문입니다.
  • 개발자 코드는 단 한 줄도 수정 불필요. npm update만으로 CI/CD 빌드 시간 10배 단축 혜택을 누릴 수 있습니다.

최근 개발자 커뮤니티를 뜨겁게 달군 소식이 하나 있습니다. 자바스크립트 생태계의 기둥이자 우리 모두의 ‘구원자’인 TypeScript가 정작 자신의 심장인 TypeScript 컴파일러(tsc)를 구동하기 위해 Node.js를 버리고 Go 언어로 재작성하기로 결정했다는 소식입니다.

“TypeScript로 만든 툴을 TypeScript가 아닌 다른 언어로 만든다고?”라는 의문이 드는 것은 당연합니다. 하지만 이 결정을 발표한 사람이 다름 아닌 TypeScript의 아버지 앤더스 하일스버그(Anders Hejlsberg)라는 점에서 무게감이 달라집니다. 이미 우리에겐 esbuildswc처럼 Go나 Rust로 무장한 초고속 빌드 도구들이 익숙하지만, TypeScript 컴파일 속도의 핵심인 ‘타입 체킹’까지 Go로 옮겨가며 10배(10x) 이상의 성능 향상을 목표로 한다는 점은 프론트엔드 생태계 전체에 영향을 미칩니다.

TypeScript 고퍼 마스코트와 Go 언어 로고가 우주 공간에서 빛나는 미래적인 테크 일러스트, 컴파일러 기어와 10x 속도 향상을 상징하는 이미지

TypeScript 7.0 — tsc가 Go로 재탄생하며 프론트엔드 컴파일 패러다임이 바뀝니다

💡 요약: TypeScript가 Go를 선택한 이유는 무엇인가요?

  • Go의 강력한 멀티코어 병렬 처리 능력을 통해 CPU 집약적인 타입 체킹 속도를 극대화하기 위해서입니다.
  • V8 엔진의 가비지 컬렉션(GC) 오버헤드를 줄이고, 컴파일러에 최적화된 Go의 자체 GC와 저수준 메모리 관리가 필요했기 때문입니다.
  • 프로젝트 규모가 커질수록 기하급수적으로 늘어나는 tsc의 실행 시간을 1/10 수준으로 단축하여 개발자 경험(DX)을 혁신하기 위함입니다.

Node.js의 한계 — 왜 기존 tsc는 점점 느려졌나?

우리가 매일 사용하는 tsc는 사실 태생적으로 엄청난 짐을 지고 있었습니다. 프로젝트가 작을 때는 문제가 없지만, 엔터프라이즈급 대규모 프로젝트로 넘어가면 이야기가 완전히 달라집니다. 코드 생산성을 높여주던 TypeScript가 역설적으로 컴파일 시간을 수분에서 수십 분까지 잡아먹으며 개발 흐름을 끊는 주범이 되곤 했죠.

가장 큰 문제는 싱글 스레드(Single-thread) 기반의 JavaScript 구조에 있습니다. TypeScript 컴파일러 작업은 수많은 파일의 추상 구문 트리(AST, Abstract Syntax Tree)를 순회하며 복잡한 타입 관계를 추론해야 하는 전형적인 CPU 집약적 작업입니다. 하지만 Node.js 환경에서 돌아가는 기존 tsc는 이 방대한 작업을 병렬로 처리하는 데 한계가 명확했습니다. 최신 CPU의 수많은 코어를 두고도 한 코어만 혼자 일하는 구조였습니다.

10만 줄 규모의 프로젝트에서 전체 타입 체크를 수행할 때 기존 tsc는 수십 초 이상 소요됩니다. Vercel, Airbnb 같은 대형 모노레포 환경에서는 TypeScript 컴파일 시간이 5~10분에 달하는 사례도 보고되고 있습니다.

또한, Node.js의 메모리 관리 방식(V8 GC) 역시 컴파일러라는 특수한 작업에는 최적화되어 있지 않습니다. 컴파일 과정에서는 수억 개의 작은 객체들이 생성·소멸하며 복잡한 참조 관계를 맺습니다. V8 엔진의 가비지 컬렉터는 웹 페이지의 생명주기에 맞춰 설계되었기에, 거대한 AST 데이터와 포인터 체이싱(Pointer Chasing)을 감당하다 보면 ‘Stop-the-world’ 현상이 잦아지고 전체 성능을 갉아먹게 됩니다.

프로젝트가 100만 줄 단위를 넘어서는 순간, 메모리 부족(OOM) 오류를 피하기 위해 --max-old-space-size 옵션을 조절하며 씨름해야 했던 경험이 바로 이런 구조적 한계에서 비롯된 것입니다.

Node.js 싱글 스레드 CPU 병목과 Go 멀티코어 병렬 처리를 비교하는 추상적 기술 시각화, 파란색과 청록색 3D 기하학적 형태

Node.js 싱글 스레드 구조(좌)와 Go Goroutine 병렬 처리(우) — TypeScript 컴파일 성능 차이의 근본 원인

언어 선택의 철학 — 왜 대세인 Rust가 아니라 Go일까?

최근 성능이 중요한 도구들을 만든다고 하면 다들 “당연히 Rust 아니야?”라고 생각하기 마련입니다. SWC나 Turbopack 같은 도구들이 이미 Rust로 엄청난 성능 향상을 보여줬으니까요. 그런데 놀랍게도 TypeScript 팀, 그리고 그 중심에 있는 Anders Hejlsberg는 차세대 컴파일러의 언어로 Go를 선택했습니다. 단순히 유행을 따르는 게 아니라, TypeScript라는 거대한 생태계를 유지보수해야 하는 입장에서 아주 현실적이고 철학적인 이유가 있었습니다.

Anders Hejlsberg는 “우리는 당연히 Rust도 심도 있게 검토했지만, 최종적으로 Go를 선택했다”라고 밝혔습니다. 가장 큰 이유는 바로 포팅(Porting)의 용이성입니다. 현재의 TypeScript 컴파일러는 가비지 컬렉션(GC) 기반인 JavaScript로 작성되어 있습니다. 수많은 객체와 AST 노드들이 서로 복잡하게 참조하며 힙(Heap) 메모리 위에서 살아가고 있습니다.

만약 이걸 Rust로 옮긴다면? Rust의 엄격한 Borrow Checker와 소유권 모델은 메모리 안전성에는 최고지만, 기존 TypeScript 컴파일러의 복잡한 참조 구조를 그대로 옮기기엔 엄청난 난이도를 선사합니다. 모든 곳에 Rc<RefCell<T>>Arc를 도배해야 하는 상황이 됩니다. 반면 Go는 자체적인 GC를 지원합니다. 덕분에 기존 JavaScript 기반의 로직을 논리적으로 거의 1:1에 가깝게 Go의 Struct와 포인터 구조로 매핑할 수 있었습니다.

특히 핵심 통찰은 AST 구조의 유사성에 있습니다. TypeScript의 AST 노드들은 Go의 Struct와 구조적으로 매우 잘 맞아떨어져서, 포팅 과정에서의 공수를 최소화하면서도 성능은 극대화할 수 있었습니다. 여기에 Go의 전매특허인 Goroutine은 병렬 AST 순회(Parallel AST Traversal)에서 진가를 발휘합니다. 수만 줄의 코드를 여러 코어에서 동시에 분석할 때, Go의 경량 스레드 모델은 복잡한 동기화 코드 없이도 압도적인 Go 컴파일러 성능을 뽑아냅니다.

비교 항목RustGo ✓ 선택
메모리 관리소유권 및 빌림 (Strict)가비지 컬렉션 (GC) 지원
동시성 모델Async/Await, ThreadsGoroutine (경량 스레드)
포팅 난이도 (from JS)매우 높음 (구조 재설계 필요)낮음 (로직 유지 용이)
컴파일 속도 (언어 자체)느림 (LLVM 기반 최적화)매우 빠름
AST 매핑 용이성어려움 (Tree 구조 소유권 관리)매우 용이 (Struct 기반)
학습 곡선높음 (고급 개념 다수)낮음 (단순 명료)
개발 생산성보통 (안전성 중심)매우 높음 (빠른 이터레이션)

내 코드도 바꿔야 할까? — TypeScript 7.0 실무 영향

이런 엄청난 변화가 예고되면 개발자들은 겁부터 납니다. “설마 또 문법이 바뀌는 거야? 내 프로젝트 다 깨지는 거 아냐?” 결론부터 말하자면, 전혀 걱정할 필요 없습니다. 이번 변화는 자동차의 디자인을 바꾸는 게 아니라, 낡은 엔진을 슈퍼카의 엔진으로 통째로 교체하는 것과 같습니다. 여러분의 TypeScript 코드는 단 한 줄도 고칠 필요가 없습니다.

이 혁신적인 프로젝트의 이름은 Project Corsa입니다. TypeScript 7.0의 핵심이 될 Go 기반 컴파일러 재작성 프로젝트입니다. 가장 큰 혜택은 역시 속도입니다. 구체적인 수치로 보면 대규모 프로젝트 기준으로 CI/CD 빌드 시간이 약 10배 단축될 것으로 기대됩니다. 지금 3분이나 걸리던 TypeScript 빌드 시간이 단 18초 만에 끝나는 것과 같습니다.

속도 향상은 빌드뿐만 아니라 IDE(VS Code 등)에서의 경험도 완전히 바꿔놓을 것입니다. 파일을 저장하자마자 에러를 표시하는 실시간 타입 체킹 속도가 비약적으로 빨라지고, Incremental compilation(증분 컴파일)의 효율도 극대화되어 수정된 부분만 즉시 반영됩니다. 대형 모노레포를 운영하는 팀이라면 이는 개발자 경험(DX)의 혁신입니다.

마이그레이션 고통은 제로입니다. 별도의 변환 도구나 설정 변경 없이, 그저 npm update typescript@7 명령 하나만으로 이 모든 TypeScript 컴파일 속도 향상의 혜택을 누릴 수 있게 됩니다.

프론트엔드 툴체인의 탈(脫) JS — Go의 부상이 시사하는 것

최근 몇 년간 프론트엔드 생태계는 거대한 ‘대이주’를 겪고 있습니다. 과거 Webpack과 Babel이 지배하던 시절, 우리에게 익숙했던 JavaScript 기반의 툴체인들은 이제 성능의 한계에 부딪혀 역사의 뒤안길로 사라지고 있습니다.

  • esbuild (Go): Webpack보다 100배 가까운 속도 향상
  • Bun (Zig): 초고속 JS 런타임 + 패키지 매니저
  • swc, Biome, Rolldown (Rust): Babel·ESLint·Rollup의 네이티브 대체재
  • tsc → Go (Project Corsa): 이제 TypeScript 컴파일러 자체까지

프론트엔드 툴체인 진화 — esbuild Go, Bun Zig, swc Rust 아이콘들이 우주 공간에 떠있고 JavaScript에서 네이티브 언어로 이주하는 화살표가 표시된 사이버펑크 일러스트

프론트엔드 툴체인의 네이티브 언어 이주 — esbuild(Go), Bun(Zig), swc(Rust), 그리고 이제 tsc(Go)까지

여기에 Microsoft가 tsc의 코어 로직을 Go로 재작성하기 시작했다는 사실은 매우 상징적입니다. 이는 단순한 개별 프로젝트의 변화를 넘어 하나의 거대한 ‘패턴’이 완성되었음을 의미합니다. 이제 “JavaScript는 런타임 언어로 살아남고, 툴체인은 네이티브 언어로 이주한다”는 공식이 정립된 것입니다.

이러한 흐름은 특히 AI 시대에 들어서며 그 중요성이 더욱 커지고 있습니다. Go가 AI 에이전트 개발 언어로 각광받는 이유에서 분석했듯, Go의 강력한 병행 처리와 실행 효율성은 AI 코드 생성 환경에서 더욱 빛을 발합니다. AI가 실시간으로 코드를 생성하고 수정하는 환경에서 빌드 도구가 1분씩 소요된다면 AI의 생산성을 온전히 누릴 수 없습니다.

GPT-5.4의 급격한 발전과 빠른 빌드 인프라의 시너지는 향후 개발 워크플로우의 핵심이 될 것입니다. AI가 생성한 수천 줄의 코드를 순식간에 타입 체크하고 빌드하여 테스트 루프를 돌리는 속도가 곧 경쟁력이 되는 시대이기 때문입니다.

마무리

결국 이번 Microsoft의 선택에서 우리가 읽어내야 할 핵심은 ‘유행보다 본질에 집중한 결단’입니다. 최근 많은 프로젝트가 Rust의 강력한 타입 시스템과 메모리 안전성을 선호하는 경향이 있지만, Microsoft는 TypeScript 컴파일러라는 거대하고 복잡한 시스템을 가장 효율적으로 이식하고 유지보수할 수 있는 균형점으로 Go를 택했습니다.

가장 세련된 도구(Rust)를 쫓기보다, 실제 성능 문제를 가장 직관적이고 빠르게 해결할 수 있는 도구(Go)를 선택하는 실용주의적 관점이 엔지니어링의 정수임을 보여준 셈입니다. Go의 부상은 프론트엔드 개발자들에게 더 이상 ‘JS/TS 세계관’에만 머물러서는 안 된다는 신호를 보내고 있습니다. 하지만 이는 위기가 아니라 기회입니다. 더 강력한 인프라를 통해 우리는 복잡한 설정과 느린 빌드에서 해방되어, 더 본질적인 비즈니스 로직과 사용자 가치에 집중할 수 있게 되었습니다.

여러분은 다음 프로젝트의 인프라 구축이나 도구 선택에 있어 Rust와 Go 중 어떤 언어를 도입하고 싶으신가요? 현업에서 느끼는 TypeScript 컴파일 속도 병목 지점은 무엇인지 댓글로 공유해 주세요.

이어지는 시리즈에서는 프론트엔드 개발자가 Go를 배워야 하는 이유를 더 깊이 다뤄보겠습니다.