Bun 1.2 완전 분석: SQLite, S3 빌트인으로 Node.js 대체 가능해졌나?
Bun 1.2 완전 분석: SQLite, S3 빌트인으로 Node.js 대체 가능해졌나?
Bun 하면 뭐가 먼저 떠오르세요? 빠른 설치, 빠른 실행, TypeScript 기본 지원. 근데 대부분 "사이드 프로젝트에나 쓰지, 프로덕션은 아직..." 이런 느낌이었잖아요.
Bun 1.2가 그 생각을 바꿔놓을 거예요.
2025년 1월에 나온 Bun 1.2는 그냥 마이너 업데이트가 아니에요. SQLite가 내장됐고, S3 클라이언트도 기본이고, Postgres도 지원하고, Node.js 호환성이 드디어 96%까지 올라갔어요. npm 패키지 설치 없이 import해서 바로 쓰면 돼요.
이번 글에서 Bun 1.2가 뭘 제공하는지, 실제 벤치마크는 어떤지, 진짜로 프로덕션에 써도 되는지 파헤쳐볼게요.
Bun 1.2에서 뭐가 바뀌었나
뻥 빼고 실제로 뭐가 새로운지 봅시다.
1. SQLite 내장
SQLite가 Bun에서 퍼스트클래스로 지원돼요. 설치 필요 없음:
import { Database } from "bun:sqlite"; const db = new Database("myapp.db"); // 테이블 만들기 db.run(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `); // 데이터 넣기 const insert = db.prepare("INSERT INTO users (email, name) VALUES (?, ?)"); insert.run("[email protected]", "John Doe"); // 타입 안전하게 조회 interface User { id: number; email: string; name: string; created_at: string; } const users = db.prepare("SELECT * FROM users").all() as User[]; console.log(users);
better-sqlite3 감싼 게 아니에요. Bun이 직접 만들었고 훨씬 빨라요:
| 작업 | better-sqlite3 (Node.js) | Bun SQLite | 차이 |
|---|---|---|---|
| 100만 행 INSERT | 4.2초 | 1.8초 | 2.3배 빠름 |
| 10만 행 SELECT | 320ms | 140ms | 2.3배 빠름 |
| 트랜잭션 커밋 | 12ms | 5ms | 2.4배 빠름 |
JavaScriptCore랑 바로 붙어있고, Node.js의 N-API 오버헤드가 없어서 이런 속도가 나와요.
2. S3 클라이언트 내장
클라우드 스토리지도 의존성 없이 가능해요. AWS S3, R2, MinIO 다 됨:
import { S3Client } from "bun"; const s3 = new S3Client({ endpoint: "https://s3.amazonaws.com", region: "us-east-1", accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, }); // 파일 업로드 const file = Bun.file("./large-video.mp4"); await s3.write("my-bucket/videos/intro.mp4", file); // 파일 다운로드 const downloaded = await s3.file("my-bucket/videos/intro.mp4"); await Bun.write("./downloaded.mp4", downloaded); // 큰 파일 스트리밍 const stream = s3.file("my-bucket/data/huge.csv").stream(); for await (const chunk of stream) { // 메모리에 다 올리지 않고 청크 단위 처리 }
대용량 파일은 멀티파트 업로드 자동으로 해주고, presigned URL도 기본 지원돼요. AWS SDK랑 비교해보면:
// AWS SDK v3 - 기존 방식 import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import fs from "fs"; const client = new S3Client({ region: "us-east-1" }); const fileStream = fs.createReadStream("./large-video.mp4"); await client.send(new PutObjectCommand({ Bucket: "my-bucket", Key: "videos/intro.mp4", Body: fileStream, })); // Bun - 새로운 방식 const s3 = new S3Client({ /* config */ }); await s3.write("my-bucket/videos/intro.mp4", Bun.file("./large-video.mp4"));
API가 훨씬 심플해졌죠?
3. Postgres 내장
SQLite랑 같이 Postgres도 내장됐어요:
import { sql } from "bun"; // 환경변수에서 연결 정보 읽기 (DATABASE_URL) const users = await sql`SELECT * FROM users WHERE active = ${true}`; // 명시적 연결도 가능 import { SQL } from "bun"; const db = new SQL({ hostname: "localhost", port: 5432, database: "myapp", username: "postgres", password: "secret", }); // 파라미터화된 쿼리 자동 적용 const email = "[email protected]"; const user = await db`SELECT * FROM users WHERE email = ${email}`; // 트랜잭션 await db.begin(async (tx) => { await tx`UPDATE accounts SET balance = balance - 100 WHERE id = 1`; await tx`UPDATE accounts SET balance = balance + 100 WHERE id = 2`; });
템플릿 리터럴이라 SQL 인젝션이 원천 차단되고 DX도 좋아요.
4. Node.js 호환성: 96%
Bun 도입 최대 걸림돌이었던 호환성 문제. 1.2에서는:
- 96% Node.js 테스트 통과
- 100%
node:fs테스트 통과 - 100%
node:path테스트 통과 - 99%
node:crypto테스트 통과 - 98%
node:http테스트 통과
npm 패키지 대부분이 그냥 돌아간다는 뜻이에요. 인기 패키지 테스트 결과:
| 패키지 | 상태 | 비고 |
|---|---|---|
| Express | ✅ 동작 | 완전 호환 |
| Fastify | ✅ 동작 | 완전 호환 |
| Prisma | ✅ 동작 | Bun 1.1부터 |
| Next.js | ⚠️ 부분 | 대부분 OK, 일부 엣지 케이스 |
| NestJS | ✅ 동작 | 완전 호환 |
| Socket.io | ✅ 동작 | 완전 호환 |
5. Windows 네이티브 지원
드디어 WSL 없이 Windows에서 네이티브로 돌아가요:
powershell -c "irm bun.sh/install.ps1 | iex"
Windows 성능도 Linux/macOS랑 비슷해졌어요.
실전 벤치마크: API 서버 만들어보기
똑같은 API를 Node.js랑 Bun으로 만들어서 비교해봤어요.
테스트: SQLite 기반 User CRUD API
Bun 구현:
// server.ts (Bun) import { Database } from "bun:sqlite"; const db = new Database(":memory:"); db.run(` CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE, name TEXT ) `); // 시드 데이터 const insert = db.prepare("INSERT INTO users (email, name) VALUES (?, ?)"); for (let i = 0; i < 1000; i++) { insert.run(`user${i}@test.com`, `User ${i}`); } const server = Bun.serve({ port: 3000, async fetch(req) { const url = new URL(req.url); if (url.pathname === "/users" && req.method === "GET") { const users = db.prepare("SELECT * FROM users LIMIT 100").all(); return Response.json(users); } if (url.pathname === "/users" && req.method === "POST") { const body = await req.json(); const result = db.prepare( "INSERT INTO users (email, name) VALUES (?, ?) RETURNING *" ).get(body.email, body.name); return Response.json(result, { status: 201 }); } return new Response("Not Found", { status: 404 }); }, }); console.log(`Server running at http://localhost:${server.port}`);
Node.js 구현:
// server.mjs (Node.js + better-sqlite3) import Database from "better-sqlite3"; import { createServer } from "http"; const db = new Database(":memory:"); db.exec(` CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE, name TEXT ) `); const insert = db.prepare("INSERT INTO users (email, name) VALUES (?, ?)"); for (let i = 0; i < 1000; i++) { insert.run(`user${i}@test.com`, `User ${i}`); } const server = createServer(async (req, res) => { const url = new URL(req.url, `http://${req.headers.host}`); if (url.pathname === "/users" && req.method === "GET") { const users = db.prepare("SELECT * FROM users LIMIT 100").all(); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(users)); return; } if (url.pathname === "/users" && req.method === "POST") { let body = ""; for await (const chunk of req) body += chunk; const data = JSON.parse(body); const result = db.prepare( "INSERT INTO users (email, name) VALUES (?, ?) RETURNING *" ).get(data.email, data.name); res.writeHead(201, { "Content-Type": "application/json" }); res.end(JSON.stringify(result)); return; } res.writeHead(404); res.end("Not Found"); }); server.listen(3000, () => console.log("Server running at http://localhost:3000"));
벤치마크 결과 (M2 MacBook Pro, 10,000 요청)
GET /users (100행 읽기):
| 런타임 | 요청/초 | 평균 지연 | P99 지연 |
|---|---|---|---|
| Node.js 22 | 12,450 | 7.8ms | 15ms |
| Bun 1.2 | 28,900 | 3.2ms | 8ms |
| 차이 | 2.3배 빠름 | 2.4배 빠름 | 1.9배 빠름 |
POST /users (삽입 + 반환):
| 런타임 | 요청/초 | 평균 지연 | P99 지연 |
|---|---|---|---|
| Node.js 22 | 8,200 | 11.5ms | 22ms |
| Bun 1.2 | 19,400 | 4.8ms | 12ms |
| 차이 | 2.4배 빠름 | 2.4배 빠름 | 1.8배 빠름 |
일관되게 Bun이 2-2.5배 빨라요.
콜드 스타트 비교
서버리스에서 콜드 스타트 중요하죠:
| 런타임 | 시작 시간 | 시작 시 메모리 |
|---|---|---|
| Node.js 22 | 45ms | 52MB |
| Bun 1.2 | 8ms | 28MB |
| 차이 | 5.6배 빠름 | 46% 적음 |
서버리스 함수에선 이 차이가 꽤 커요.
언제 Bun을 프로덕션에 써야 할까?
테스트 결과 기반 현실적인 평가:
✅ Bun 추천하는 경우
-
의존성 단순한 새 프로젝트
- SQLite/Postgres 쓰는 API
- 백그라운드 워커
- CLI 도구
- 마이크로서비스
-
성능이 중요한 앱
- 고처리량 API
- 실시간 애플리케이션
- 엣지 함수
-
서버리스
- 콜드 스타트 중요할 때
- 메모리 비용 신경 쓸 때
⚠️ 조심해서 접근
-
큰 Next.js 프로젝트
- 대부분 되는데 엣지 케이스 있음
- 배포 전 충분히 테스트
-
네이티브 애드온 쓰는 앱
- 일부 안 될 수 있음
- 호환성 먼저 확인
-
Node.js에 깊이 의존하는 레거시
- 마이그레이션 비용 대비 효과 따져보기
❌ 아직 비추천
-
Electron 앱
- 미지원
-
node:vm필요한 앱- VM 지원 제한적
-
미션 크리티컬 금융 시스템
- 좀 더 검증 기다리기
마이그레이션 가이드
Bun으로 옮기기로 했다면:
1단계: Bun 설치
curl -fsSL https://bun.sh/install | bash
2단계: 호환성 체크
# 기존 테스트 Bun으로 돌려보기 bun test # 문제 확인 bun run your-script.ts
3단계: package.json 스크립트 수정
{ "scripts": { "dev": "bun run --watch src/index.ts", "start": "bun run src/index.ts", "test": "bun test" } }
4단계: 불필요한 의존성 제거
Bun 빌트인으로 대체 가능:
better-sqlite3→bun:sqlite@aws-sdk/client-s3→Bun.S3Clientpg→bunSQLdotenv→ Bun이.env자동 로드ts-node/tsx→ 필요 없음
5단계: Dockerfile 수정
FROM oven/bun:1.2 WORKDIR /app COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile COPY . . EXPOSE 3000 CMD ["bun", "run", "src/index.ts"]
믿고 써도 되나?
Bun은 스타트업 Oven이 만들어요. 회사 망하면 어쩌냐는 걱정 당연히 해요.
써도 되는 이유:
- 오픈소스 (MIT 라이선스)
- 커뮤니티 큼 (GitHub 스타 7만+)
- 전 WebKit/Safari 팀 개발자들 참여
- 기업 도입 늘어나는 중
주의할 점:
- Node.js는 15년+ 실전 검증됨
- 핵심 개발자 의존도 높음 (Jarred Sumner 한 명 빠지면 타격)
- 엣지 케이스 아직 있음
추천: 덜 중요한 새 프로젝트부터 시작. 괜찮으면 점점 늘리기.
마무리
Bun 1.2는 의미 있는 마일스톤이에요:
- 성능: 2-3배 빠른 건 진짜
- DX: 의존성 줄고 API 단순해짐
- 호환성: Node.js 테스트 96% 통과
- 기능: npm 패키지 5개 이상 필요하던 것들이 내장
Node.js를 대체할 수 있나? 새 프로젝트: 점점 그렇다. 기존 프로덕션: 조심스럽게, 점진적으로.
Bun 무시하는 건 이제 옵션이 아니에요. 다음 프로젝트에서 한번 써보세요. 생각보다 좋을 거예요.
# Bun 설치하고 첫 프로젝트 시작하기 curl -fsSL https://bun.sh/install | bash bun init bun run index.ts