Deno 2와 Bun을 심층 비교합니다. 아키텍처 차이, 성능 벤치마크, API 호환성, 생태계 성숙도, 그리고 프로젝트 특성에 따른 선택 기준을 제시합니다.
Node.js의 대안으로 등장한 Deno와 Bun은 각각 다른 철학으로 JavaScript 런타임의 미래를 제시하고 있습니다. Deno가 "보안과 웹 표준"을 핵심 가치로 내세운다면, Bun은 "극한의 속도와 올인원"을 무기로 삼고 있습니다.
이 장에서는 두 런타임을 아키텍처, 성능, 호환성, 생태계 측면에서 체계적으로 비교하고, 실무에서 어떤 기준으로 선택해야 하는지를 분석합니다.
가장 근본적인 차이는 JavaScript 엔진의 선택에 있습니다.
| 구성 요소 | Deno | Bun |
|---|---|---|
| JS 엔진 | V8 (Google) | JavaScriptCore (Apple) |
| 구현 언어 | Rust | Zig |
| 비동기 I/O | Tokio | io_uring (Linux) / kqueue (macOS) |
| 트랜스파일러 | SWC | 자체 구현 |
| 번들러 | 없음 (서드파티 사용) | 내장 |
V8과 JavaScriptCore(JSC)는 각각 Chrome과 Safari의 JavaScript 엔진입니다.
V8 (Deno가 사용)
- JIT 컴파일: Ignition(인터프리터) + TurboFan(최적화 컴파일러)
- 장기 실행 코드의 최적화에 강점
- 가비지 컬렉션: Orinoco (병렬, 점진적, 동시 수행)
- 메모리 사용량이 상대적으로 많음
- ECMAScript 최신 표준 구현 속도 빠름
JavaScriptCore (Bun이 사용)
- JIT 컴파일: LLInt + Baseline + DFG + FTL (4단계)
- 초기 시작 속도에 강점
- 가비지 컬렉션: Riptide (동시 수행)
- 메모리 효율성이 상대적으로 높음
- WebKit 생태계에서 검증됨JSC의 4단계 JIT 파이프라인은 초기 실행을 빠르게 시작하면서도 핫 코드를 점진적으로 최적화합니다. 이것이 Bun의 빠른 시작 시간에 기여하는 요소 중 하나입니다.
두 런타임의 네이티브 코드 구현 언어 선택도 흥미롭습니다.
Rust는 소유권 시스템과 차용 검사기(Borrow Checker)를 통해 컴파일 타임에 메모리 안전성을 보장합니다. Zig는 C의 대안으로 설계된 언어로, 메모리 할당을 명시적으로 관리하면서도 C보다 안전한 패턴을 제공합니다. Zig는 런타임 오버헤드를 최소화하는 데 초점을 맞추고 있어 Bun의 성능 목표와 잘 맞습니다.
HTTP 서버 처리량은 런타임 선택에서 가장 자주 비교되는 지표입니다.
// Deno
Deno.serve({ port: 3000 }, () => {
return new Response("Hello, World!");
});// Bun
Bun.serve({
port: 3000,
fetch() {
return new Response("Hello, World!");
},
});단순 텍스트 응답 (requests/sec, 높을수록 좋음)
Bun: ~110,000 req/s
Deno: ~85,000 req/s
Node.js: ~45,000 req/s
JSON 응답 (requests/sec)
Bun: ~95,000 req/s
Deno: ~72,000 req/s
Node.js: ~38,000 req/s벤치마크 수치는 하드웨어, OS, 커널 버전, 런타임 버전, 측정 도구에 따라 크게 달라질 수 있습니다. 위 수치는 일반적인 경향을 보여주기 위한 참고 자료이며, 실제 프로덕션 워크로드에서의 성능은 애플리케이션의 특성에 따라 다를 수 있습니다. 반드시 자신의 환경에서 직접 벤치마크를 수행하세요.
콜드 스타트(Cold Start) 시간은 서버리스 환경에서 특히 중요합니다.
빈 스크립트 실행 시간
Bun: ~10ms
Deno: ~25ms
Node.js: ~35ms
TypeScript 파일 실행 시간
Bun: ~15ms
Deno: ~30ms
Node.js: ~200ms+ (tsc 컴파일 포함)Bun이 시작 시간에서 가장 빠른 이유는 JSC 엔진의 빠른 초기화와 Zig로 구현된 트랜스파일러의 낮은 오버헤드 때문입니다.
express + 의존성 설치
bun install: ~0.5초
deno add: ~2초 (글로벌 캐시에 저장)
npm install: ~8초
pnpm install: ~4초Bun의 패키지 설치 속도가 압도적인 이유는 Zig로 구현된 패키지 해석기, 시스템 콜 최적화, 그리고 병렬 다운로드 전략 때문입니다.
단순 벤치마크와 실제 워크로드의 성능은 다를 수 있습니다.
데이터베이스 I/O가 포함된 API 서버
- 런타임 차이보다 DB 쿼리 시간이 지배적
- 런타임 간 차이는 5-15% 수준으로 줄어듬
복잡한 비즈니스 로직 처리
- V8의 장기 실행 최적화가 유리할 수 있음
- JSC의 빠른 시작은 서버리스에서 유리
대용량 파일 처리
- 스트리밍 처리 성능은 I/O 레이어에 따라 다름
- Bun의 io_uring (Linux)이 특정 패턴에서 유리두 런타임 모두 Node.js 호환을 지향하지만, 접근 방식과 범위가 다릅니다.
// fs 모듈 - 두 런타임 모두 지원
import { readFileSync } from "node:fs";
const content = readFileSync("./data.json", "utf-8"); // Deno, Bun 모두 동작
// child_process - 호환 수준 차이 있음
import { exec } from "node:child_process";
exec("ls -la", (err, stdout) => {
console.log(stdout);
}); // Bun이 더 넓은 호환성
// node:crypto - 두 런타임 모두 지원
import { createHash } from "node:crypto";
const hash = createHash("sha256").update("data").digest("hex");| 호환성 영역 | Deno | Bun |
|---|---|---|
| node:fs | 대부분 지원 | 거의 완벽 |
| node:http | 지원 | 거의 완벽 |
| node:crypto | 지원 | 거의 완벽 |
| node:net | 부분 지원 | 거의 완벽 |
| node:child_process | 부분 지원 | 대부분 지원 |
| 네이티브 모듈 (C++) | 제한적 | 부분 지원 (N-API) |
| npm 생태계 호환 | 90%+ | 95%+ |
Bun은 Node.js "드롭인 대체(drop-in replacement)"를 목표로 하기 때문에, Node.js API 호환성에서 더 넓은 범위를 지원합니다. Deno는 호환성보다 웹 표준 준수에 우선순위를 두므로, Node.js 전용 API보다는 Deno.* API와 웹 표준 API를 먼저 사용할 것을 권장합니다.
// Deno.serve - 웹 표준 기반 HTTP 서버
Deno.serve((req) => new Response("Hello"));
// Deno.KV - 내장 키-값 저장소
const kv = await Deno.openKv();
await kv.set(["key"], "value");
// Deno.permissions - 런타임 권한 관리
const status = await Deno.permissions.query({ name: "read" });// Bun.serve - Bun 최적화 HTTP 서버
Bun.serve({
fetch(req) { return new Response("Hello"); },
});
// Bun.file - 최적화된 파일 API
const file = Bun.file("./data.json");
const text = await file.text();
// Bun.build - 내장 번들러
await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
});
// Bun.password - 내장 비밀번호 해싱
const hash = await Bun.password.hash("password123");
const isValid = await Bun.password.verify("password123", hash);| 도구 | Deno | Bun |
|---|---|---|
| 포매터 | 내장 (dprint) | 없음 (Prettier 등 외부) |
| 린터 | 내장 (deno_lint) | 없음 (ESLint 등 외부) |
| 테스트 러너 | 내장 | 내장 (Jest 호환) |
| 벤치마크 | 내장 | 없음 |
| 번들러 | 없음 | 내장 |
| 패키지 매니저 | 내장 (deno add) | 내장 (bun install) |
| 타입 체크 | 내장 | 없음 (tsc 사용) |
Deno는 개발 워크플로우 전반의 도구를 내장하고, Bun은 번들러와 초고속 패키지 매니저에 집중합니다.
import { assertEquals } from "jsr:@std/assert";
Deno.test("숫자 덧셈", () => {
assertEquals(1 + 2, 3);
});
Deno.test("비동기 테스트", async () => {
const data = await Promise.resolve(42);
assertEquals(data, 42);
});import { expect, test, describe } from "bun:test";
describe("산술 연산", () => {
test("숫자 덧셈", () => {
expect(1 + 2).toBe(3);
});
test("비동기 테스트", async () => {
const data = await Promise.resolve(42);
expect(data).toBe(42);
});
});Bun의 테스트 러너는 Jest와 호환되는 API를 제공하므로, 기존 Jest 테스트를 거의 수정 없이 실행할 수 있습니다. Deno의 테스트 러너는 자체 API를 사용하지만, 권한 설정이나 리소스 정리 같은 기능을 테스트 단위로 제어할 수 있는 장점이 있습니다.
웹 프레임워크
Deno: Fresh (네이티브), Hono, Oak
Bun: Elysia (네이티브), Hono, Express
프론트엔드
Deno: Fresh (Preact), Vite (호환)
Bun: Vite (빠른 실행), Next.js (실험적)
ORM/데이터베이스
Deno: Deno KV (내장), deno-postgres, Drizzle
Bun: Bun SQLite (내장), Prisma, DrizzleDeno
- Deno Deploy (공식, 엣지 배포)
- Docker (범용)
- deno compile (단일 바이너리)
Bun
- Docker (범용)
- Vercel (부분 지원)
- Railway, Fly.io (커뮤니티 지원)Deno는 Deno Deploy라는 공식 엣지 배포 플랫폼을 보유하고 있어, 배포 파이프라인까지 일관된 경험을 제공합니다. Bun은 아직 공식 배포 플랫폼이 없지만, Docker를 통한 범용 배포가 가능합니다.
- 보안이 최우선 과제인 프로젝트
- 웹 표준 기반의 이식성 있는 코드를 작성하고 싶을 때
- 포매터, 린터, 테스트까지 내장된 통합 도구 체인이 필요할 때
- Deno Deploy를 통한 엣지 배포를 계획할 때
- 깔끔한 TypeScript 개발 환경을 원할 때
- 코드 품질과 표준 준수를 중시하는 팀- 극한의 성능이 최우선인 프로젝트
- 기존 Node.js/Express 프로젝트의 드롭인 대체가 필요할 때
- 번들러까지 내장된 올인원 도구가 필요할 때
- 패키지 설치 속도가 중요한 CI/CD 환경
- Jest 기반 테스트를 그대로 유지하고 싶을 때
- 빠른 프로토타이핑을 원하는 개인 프로젝트- TypeScript 네이티브 지원이 필요한 프로젝트
- Node.js의 레거시에서 벗어나고 싶을 때
- 새로운 프로젝트를 시작할 때
- 현대적인 JavaScript 런타임을 경험하고 싶을 때최종 선택은 기술적 우열이 아니라 프로젝트의 요구사항, 팀의 역량, 배포 환경, 장기적 유지보수 계획 등을 종합적으로 고려하여 결정해야 합니다. 두 런타임 모두 활발히 발전하고 있으므로, 현재의 차이가 미래에도 유지될 것이라고 단정하기 어렵습니다.
Deno와 Bun의 경쟁은 JavaScript 생태계 전체에 긍정적인 영향을 미치고 있습니다. Node.js도 이들의 자극을 받아 ESM 지원 강화, 실험적 권한 모델 도입, 내장 테스트 러너 추가 등의 개선을 진행하고 있습니다.
WinterCG 표준화의 진행과 함께, 장기적으로는 어떤 런타임을 사용하든 핵심 코드를 이식할 수 있는 환경이 만들어질 것으로 기대됩니다.
다음 장에서는 Deno 네이티브 웹 프레임워크인 Fresh를 살펴봅니다. Islands Architecture를 기반으로 한 이 프레임워크가 어떻게 현대적인 웹 개발을 지원하는지 분석합니다.
이 글이 도움이 되셨나요?
Deno가 채택한 웹 표준 API(fetch, WebSocket, Web Crypto, Streams)와 Deno 전용 API(Deno.serve, Deno.KV, Deno.open)를 심층적으로 분석합니다.
Deno의 공식 웹 프레임워크 Fresh를 심층 분석합니다. Islands Architecture, Preact 기반 컴포넌트, 라우팅, 미들웨어, 데이터 페칭 등 핵심 기능을 다룹니다.
Deno Deploy를 중심으로 서버리스 및 엣지 배포 전략을 다룹니다. 엣지 컴퓨팅 개념, 콜드 스타트 성능, Deno KV를 활용한 엣지 상태 관리, Cloudflare Workers 호환성을 분석합니다.