가장 흥미로운 최신 개발 도구 중 하나는 Bun입니다. Bun은 개발자 생산성과 애플리케이션 성능을 향상시키기 위해 설계된 매우 빠르고 올인원 JavaScript 툴킷입니다. Bun은 단순한 또 다른 런타임이 아닙니다. 단일 네이티브 실행 파일 내에 런타임, 번들러, 테스트 러너, 패키지 관리자 등을 모두 포함하는 응집력 있는 생태계입니다. 이 가이드에서는 Bun의 핵심 개념과 강력한 API에 중점을 두고 Bun의 필수 사항을 안내합니다.
개발팀이 최대한의 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하시나요?
Apidog는 여러분의 모든 요구를 충족하며, 훨씬 저렴한 가격으로 Postman을 대체합니다!
Bun이란 무엇인가요?

Bun의 핵심은 고성능 JavaScript 런타임 엔진을 중심으로 구축되었습니다. Google의 V8 엔진을 사용하는 Node.js와 달리 Bun은 Safari를 구동하는 Apple의 JavaScriptCore(JSC)를 활용합니다. 이러한 선택은 Bun이 저수준 Zig 프로그래밍 언어로 구현된 것과 결합되어 놀라운 속도에 크게 기여합니다. Bun 애플리케이션의 시작 시간은 종종 동등한 Node.js 애플리케이션보다 훨씬 빠르며, 때로는 4배 이상 빠르기도 합니다. 이러한 속도 이점은 시작 시간 외에도 확장됩니다. Bun의 다양한 API 내부 구현은 최대 처리량과 최소 메모리 사용량을 위해 최적화되어 있습니다.
그러나 Bun의 야망은 단순히 더 빠른 런타임을 넘어섭니다. 포괄적인 툴킷이 되어 일반적인 개발자 요구 사항을 직접 해결하는 것을 목표로 합니다.
- 통합 도구:
bun
명령어 자체는 수많은 기능의 진입점 역할을 합니다.bun run
은package.json
에 정의된 스크립트를 실행하고,bun install
은 종속성을 관리하며(종종 npm이나 yarn보다 훨씬 빠름),bun test
는 Jest 호환 API를 사용하여 테스트를 실행하고,bun build
는 프로덕션용 코드를 번들링하며,bunx
는 명시적으로 설치하지 않고 패키지를 실행합니다. 이러한 통합은 필요한 개별 개발 도구의 수를 줄여 워크플로우를 단순화합니다. - 네이티브 TypeScript 및 JSX 지원: Bun의 뛰어난 기능 중 하나는 TypeScript(
.ts
,.tsx
) 및 JSX(.jsx
) 파일에 대한 기본 지원입니다. Bun에는 실행 또는 번들링 중에 이러한 파일 형식을 원활하게 처리하는 내장된 고도로 최적화된 트랜스파일러가 포함되어 있습니다. 이를 통해 많은 일반적인 개발 시나리오에서tsc
또는 Babel을 포함하는 별도의 컴파일 단계가 필요 없으므로 설정 프로세스가 간소화됩니다. - 모듈 시스템 호환성: Bun은 ES Modules(ESM)에 대한 일류 지원을 통해 최신 JavaScript를 수용합니다. 그러나 CommonJS(CJS)를 기반으로 구축된 방대한 기존 생태계를 인식하고 있습니다. Bun은 두 모듈 시스템 모두에 대한 강력한 호환성을 제공하여 개발자가
import
와require
를 거의 상호 교환적으로 사용하고 npm에서 사용할 수 있는 수백만 개의 기존 CJS 패키지를 활용할 수 있도록 합니다. - 웹 표준 API 준수: 핵심 설계 원칙은 표준 웹 API 구현입니다.
fetch
,Request
,Response
,Headers
,WebSocket
, Streams API(ReadableStream
,WritableStream
)와 같은 함수 및 객체는 Bun 전역 범위에 내장되어 있습니다. 이는 서버 측 Bun 환경, 브라우저 프론트엔드, 엣지 컴퓨팅 플랫폼 간의 코드 이식성을 촉진하여 개발자가 다양한 컨텍스트에서 익숙한 API를 재사용할 수 있도록 합니다. - Node.js 호환성: Bun은 최적화된 API와 웹 표준을 통해 자체 경로를 개척하는 동시에 Node.js API 표면과의 높은 수준의 호환성을 목표로 합니다. 많은 내장 Node.js 모듈(
node:fs
,node:path
,node:os
,node:events
등) 및 전역 객체(process
,Buffer
,__filename
,__dirname
)는 부분적으로 또는 완전히 구현되었습니다. 목표는 많은 기존 Node.js 프로젝트와 npm 패키지를 최소한의 수정 또는 수정 없이 Bun에서 실행할 수 있도록 하여 Bun을 수많은 경우에 잠재적인 "드롭인 대체"로 포지셔닝하는 것입니다.
이러한 요소를 결합함으로써 Bun은 성능, 단순성 및 현대적인 개발 경험을 추구하는 JavaScript 및 TypeScript 개발자에게 매력적인 대안을 제시합니다.

Bun 설치 방법
Bun 시작은 다양한 플랫폼에서 빠르고 간단하게 설계되었습니다. macOS, Linux 및 Windows Subsystem for Linux(WSL)에서 가장 일반적인 방법은 터미널에서 간단한 curl
명령어를 실행하는 것입니다.
curl -fsSL https://bun.sh/install | bash
이 명령어는 설치 스크립트를 다운로드하여 bash
로 직접 파이프합니다. 스크립트는 운영 체제 및 아키텍처 감지를 처리하고, 적절한 Bun 실행 파일을 다운로드하며, 일반적으로 ~/.bun/bin
에 설치합니다. 또한 시스템의 PATH
에 ~/.bun/bin
을 추가하기 위해 셸 구성 파일(예: .zshrc
, .bashrc
또는 .bash_profile
)을 업데이트하려고 시도하여 bun
명령어를 전역적으로 사용할 수 있도록 합니다. 변경 사항이 즉시 적용되도록 터미널 세션을 다시 시작하거나 셸 구성 파일을 수동으로 소스해야 할 수 있습니다(예: source ~/.zshrc
).
권한 문제가 발생하거나 bash
로 직접 파이프하는 것을 선호하지 않는 경우, 먼저 스크립트를 다운로드하고 실행하기 전에 검사할 수 있습니다.
curl -fsSL https://bun.sh/install -o install.sh
# 원하는 경우 install.sh 검사
bash install.sh
기타 설치 방법:
- NPM: 주로 독립형 도구로 의도되었지만, Node.js 및 npm이 이미 있는 환경에서는 npm을 통해 Bun을 전역적으로 설치할 수도 있습니다.
npm install -g bun
- Docker: 공식 Bun Docker 이미지는 Docker Hub에서 사용할 수 있으며, Bun이 사전 설치된 격리된 환경을 제공합니다. 이는 컨테이너화된 개발 및 배포 워크플로우에 유용합니다. 다양한 기본 OS 배포판(예: Debian, Alpine) 및 특정 Bun 버전에 해당하는 태그를 기반으로 하는 다양한 이미지를 찾을 수 있습니다.
docker run --rm --init --ulimit memlock=-1:-1 oven/bun:latest bun --version
- Windows: Bun에 대한 네이티브 Windows 지원은 아직 실험 단계로 간주되지만 적극적으로 개발되고 있습니다. 현재 Windows에서 Bun을 사용하는 권장 방법은 WSL을 통하는 것입니다. 그러나 직접 Windows 빌드가 제공되고 있으며, 설치 프로세스에는
.zip
아카이브 다운로드 및 시스템PATH
에 실행 파일 위치를 수동으로 추가하는 작업이 포함될 수 있습니다. 네이티브 Windows 설치의 최신 상태 및 지침은 공식 Bun 문서를 확인하십시오. - Homebrew (macOS): macOS에서 Homebrew를 사용하는 경우, 해당 탭을 통해 Bun을 설치할 수 있습니다.
brew tap oven-sh/bun
brew install bun
확인:
설치 후 새 터미널 창을 열고 버전을 확인하여 설치를 확인하십시오.
bun --version
이렇게 하면 설치된 버전 번호가 출력되어 Bun을 사용할 준비가 되었음을 확인합니다. bun --help
를 실행하여 사용 가능한 명령어 및 옵션 목록을 볼 수도 있습니다.
Bun을 처음 실행해 보세요
Bun으로 간단한 프로그램을 작성하고 실행해 보겠습니다. 가장 일반적인 작업 중 하나는 HTTP 서버를 만드는 것입니다. Bun은 이 목적을 위해 내장된 고도로 최적화된 API인 Bun.serve
를 제공합니다.
server.js
(또는 Bun이 둘 다 처리하므로 server.ts
)라는 새 파일을 만드십시오.
// server.ts
// Bun.serve는 HTTP 서버를 시작합니다.
const server = Bun.serve({
// 수신 대기할 포트를 지정합니다.
// 기본값은 process.env.PORT || 3000입니다.
port: 3000,
// 'fetch' 함수는 핵심 요청 핸들러입니다.
// 표준 Request 객체를 수신하며 Response 객체(또는 Promise로 해결되는 객체)를 반환해야 합니다.
fetch(request: Request): Response {
// 표준 웹 API Response 객체를 생성합니다.
return new Response("Welcome to Bun!");
},
});
// 서버가 실행 중임을 나타내는 메시지를 기록합니다.
console.log(`Listening on http://localhost:${server.port}`);
이 코드 스니펫은 다음을 수행합니다.
- Bun에서 HTTP 서버를 생성하기 위한 기본 함수인
Bun.serve
를 호출합니다. - 구성 객체를 전달하여
port
(이 경우 3000)를 지정합니다. - 중요한 부분은
fetch
함수입니다. 이 함수는 들어오는 모든 HTTP 요청에 대해 호출됩니다. Service Worker fetch 이벤트 핸들러 패턴과 일치하며 표준Request
객체를 받습니다. fetch
내부에서 표준Response
객체를 구성하고 반환합니다. 여기서는 단순히 일반 텍스트 "Welcome to Bun!"을 반환합니다.- 마지막으로 서버가 수신 대기하는 실제 포트(
server.port
를 통해 액세스 가능)를 포함하여 콘솔에 확인 메시지를 기록합니다.
이 서버를 실행하려면 파일이 저장된 디렉토리에서 터미널을 열고 다음을 실행하십시오.
bun run server.ts
또는 server.js
로 저장한 경우:
bun run server.js
Bun은 스크립트를 실행합니다. TypeScript(server.ts
)를 사용한 경우 Bun의 내부 트랜스파일러가 실행 전에 JavaScript로 변환하는 것을 즉시 처리합니다. "Listening on http://localhost:3000" 메시지가 표시됩니다.
이제 웹 브라우저를 열고 http://localhost:3000
으로 이동하십시오. "Welcome to Bun!" 텍스트가 표시되어야 합니다.
서버를 중지하려면 터미널로 돌아가 Ctrl + C
를 누르십시오.
이 간단한 예는 Bun으로 기본 서버를 설정하고 코드(TypeScript 포함)를 직접 실행하는 용이성을 보여주며, 통합된 특성과 Request
및 Response
와 같은 웹 표준 API에 대한 의존성을 보여줍니다.
Bun의 네이티브 TypeScript 지원은 무엇인가요?
특히 TypeScript를 이미 사용하거나 채택하려는 개발자에게 Bun의 가장 중요한 장점 중 하나는 일류의 기본 지원입니다. TypeScript를 실행하기 위해 일반적으로 TypeScript 컴파일러(tsc
)를 사용한 사전 컴파일 또는 ts-node
또는 tsx
와 같은 로더/레지스터 사용이 필요한 Node.js와 달리 Bun은 이를 네이티브하고 투명하게 처리합니다.
작동 방식:
Bun에게 .ts
또는 .tsx
파일을 실행하도록 요청하면(예: bun run myscript.ts
), Bun은 자동으로 내부 트랜스파일러를 호출합니다. 이 트랜스파일러는 네이티브 코드(Zig)로 작성되었으며 매우 빠릅니다. 그 역할은 다음과 같습니다.
- 타입 제거: 표준 JavaScript 실행의 일부가 아닌 TypeScript 타입 어노테이션, 인터페이스, enum 등을 제거합니다.
- 구문 변환: TypeScript 특정 구문(예: 특정
enum
사용 또는 구성된 경우 이전 데코레이터 구문)을 동등한 JavaScript로 변환합니다. - JSX 처리: JSX 구문(
.tsx
및.jsx
파일에서 사용됨)을 표준 JavaScript 함수 호출(일반적으로React.createElement
또는 구성된 JSX 런타임 등가)로 변환합니다.
핵심 이점은 이 작업이 실행(bun run
) 또는 번들링(bun build
) 프로세스 중에 즉시 발생한다는 것입니다. 개발 중에 TypeScript 코드를 실행하기 위해 별도의 명시적인 빌드 단계가 필요 없습니다.
예시:
이 TypeScript 파일(greet.ts
)을 고려하십시오.
// greet.ts
interface User {
name: string;
id: number;
}
function greetUser(user: User): void {
console.log(`Hello, ${user.name} (ID: ${user.id})!`);
}
const myUser: User = { name: "Bun Developer", id: 123 };
greetUser(myUser);
// Bun이 지원하는 최신 기능도 사용할 수 있습니다.
const message = `Bun version: ${Bun.version}`;
console.log(message);
이것을 직접 실행할 수 있습니다.
bun run greet.ts
Bun은 내부적으로 트랜스파일링하고 결과 JavaScript를 실행하여 다음과 같은 출력을 생성합니다.
Hello, Bun Developer (ID: 123)!
Bun version: 1.x.y
JSX 지원:
마찬가지로 JSX가 포함된 .tsx
파일이 있는 경우:
// component.tsx
// JSX가 구성되어 있다고 가정합니다 (Bun 기본값은 종종 React와 함께 작동합니다).
function MyComponent({ name }: { name: string }) {
return <div className="greeting">Hello, {name}!</div>;
}
// 참고: 이것을 직접 실행해도 HTML이 렌더링되지 않습니다.
// 트랜스파일링된 JS 구조만 보여줍니다.
// 일반적으로 더 큰 앱 또는 프레임워크 내에서 사용합니다.
console.log("컴포넌트 생성 시뮬레이션 (트랜스파일링된 출력 구조):");
// 실제 출력은 JSX 변환 설정에 따라 다르지만,
// JavaScript 객체/함수 호출이 될 것입니다.
bun run component.tsx
를 실행하면 파일이 실행되고 JSX가 JavaScript로 트랜스파일링됩니다.
구성 (tsconfig.json
):
Bun은 트랜스파일링에 영향을 미치는 구성 옵션에 대해 tsconfig.json
파일을 존중합니다. Bun은 tsc
와 같은 전체 타입 검사를 수행하지 않지만(Bun은 실행 및 트랜스파일링 속도에 중점), tsconfig.json
을 읽어 다음과 같은 설정을 이해합니다.
jsx
: ("react-jsx"
,"react"
등) JSX를 변환하는 방법.jsxImportSource
: JSX 헬퍼 함수를 가져올 모듈 (예:"react"
).experimentalDecorators
,emitDecoratorMetadata
: 데코레이터 지원.paths
,baseUrl
: 사용자 지정 가져오기 별칭에 대한 모듈 경로 매핑.target
,module
: Bun이 실행을 관리하지만, 이러한 설정은 때때로 사소한 트랜스파일링 세부 사항에 영향을 미칠 수 있습니다.strict
,strictNullChecks
등: 이러한 설정은 주로 타입 검사(Bun은run
중에 수행하지 않음)에 영향을 미치지만, 일부 관련 JavaScript emit 동작이 영향을 받을 수 있습니다.
tsconfig.json
이 없으면 Bun은 합리적인 기본 설정을 사용합니다.
이러한 원활한 통합은 Bun으로 TypeScript 프로젝트를 시작하는 것을 믿을 수 없을 정도로 간단하고 빠르게 만들며, 진입 장벽을 낮추고 개발 주기를 가속화합니다.
Bun 특정 API에 대해 이야기해 봅시다
Bun은 웹 표준 API 및 Node.js와의 호환성을 매우 강조하지만, 전역 Bun
객체 아래에 자체적으로 최적화된 내장 API 세트도 도입합니다. 이러한 API는 종종 Bun의 네이티브 코드 기능을 활용하는 일반적인 작업에 대한 고성능 대안 또는 편리한 래퍼를 제공합니다.
몇 가지 주요 Bun.*
API를 살펴보겠습니다.
Bun.serve({...})
: 퀵스타트에서 보았듯이, 이는 고성능 HTTP 및 WebSocket 서버를 구축하기 위한 초석입니다. 간소화된 구성을 제공하며 표준fetch
핸들러 시그니처를 사용합니다. (자세한 내용은 나중에 다룹니다).Bun.file(path)
: 디스크에 있는 파일에 대한 지연 참조인BunFile
객체를 생성합니다. 필요할 때만 다양한 형식(.text()
,.json()
,.arrayBuffer()
,.stream()
)으로 파일 내용을 읽기 위한 고도로 최적화된 메서드를 제공합니다. 이는 종종node:fs
등가보다 훨씬 빠릅니다.Bun.write(path, data)
:Bun.file
의 반대 개념으로, 파일에 데이터를 효율적으로 쓰기 위해 사용됩니다. 다양한 데이터 타입(문자열, Blob, Buffer, 다른BunFile
)을 허용하며 기본적으로 원자적으로 쓰기를 수행합니다.Bun.build({...})
: esbuild API와 호환되는 Bun의 내장 번들러에 대한 프로그래밍 방식 액세스를 제공합니다. Bun 스크립트 내에서 직접 브라우저 또는 다른 런타임용 JavaScript/TypeScript를 번들링할 수 있습니다.Bun.spawn({...})
/Bun.spawnSync({...})
: Node.js의child_process
와 유사하게 외부 명령어를 자식 프로세스로 실행합니다. 비동기 스트리밍 API와 간단한 동기 버전을 제공하며, 낮은 오버헤드를 위해 최적화되었습니다.Bun.Transpiler({...})
: 전체 번들링 없이 TypeScript/JSX를 JavaScript로 변환하기 위한 Bun의 빠른 내부 트랜스파일러에 대한 직접 프로그래밍 방식 액세스.Bun.password.hash(...)
/Bun.password.verify(...)
: Argon2id(권장) 및 bcrypt와 같은 산업 표준 알고리즘을 사용하여 암호를 해싱하고 확인하기 위한 안전하고 사용하기 쉬운 함수입니다. 외부 라이브러리가 필요 없습니다.Bun.env
: 환경 변수에 액세스하기 위한 객체로,process.env
와 유사하지만 일부 시나리오에서 더 빠른 액세스를 제공할 수 있습니다.Bun.version
: 현재 실행 중인 Bun 버전을 포함하는 문자열.Bun.revision
: 현재 실행 중인 Bun 빌드의 Git 커밋 해시를 포함하는 문자열.Bun.sleep(ms)
/Bun.sleepSync(ms)
: 지정된 시간 동안 실행을 일시 중지하는 함수.Bun.gc()
: 수동으로 가비지 컬렉션을 트리거합니다(디버깅/벤치마킹에 주로 사용).Bun.resolveSync(specifier, parentPath)
/Bun.resolve(specifier, parentPath)
: Node.js 스타일 모듈 해석을 프로그래밍 방식으로 수행하여 모듈의 절대 경로를 찾습니다.
이러한 API는 일반적인 개발 작업에 대한 최적화된 내장 솔루션을 제공하여 외부 종속성에 대한 의존도를 줄이고 네이티브 코어의 속도를 활용하려는 Bun의 노력을 나타냅니다.
Bun의 웹 API
Bun의 근본적인 설계 선택 중 하나는 표준 웹 API 구현에 대한 강력한 약속입니다. 특정 작업(특히 네트워킹 및 데이터 처리)에 대한 표준 API가 존재하는 경우, Bun은 독점 API를 발명하거나 Node.js 규칙에만 의존하기보다는 해당 표준을 구현하는 것을 선호합니다.
이 접근 방식은 몇 가지 중요한 장점을 제공합니다.
- 코드 이식성: 표준 웹 API를 사용하여 작성된 코드는 브라우저, Node.js(점점 웹 표준을 채택하고 있음), Deno, Cloudflare Workers 및 Bun과 같은 다양한 JavaScript 환경에서 수정 없이 재사용될 수 있습니다.
- 익숙함: 브라우저 API에 이미 익숙한 개발자는 Bun으로 작업할 때 해당 지식을 활용하여 학습 곡선을 줄일 수 있습니다.
- 미래 보장: WHATWG 및 W3C와 같은 기관에서 설정한 표준에 맞춰 정렬하면 일반적으로 장기적으로 더 안정적이고 널리 지원되는 API가 됩니다.
- 성능: Bun의 이러한 웹 API 네이티브 구현은 런타임에 대해 고도로 최적화되어 있습니다.
Bun에 구현된 주요 웹 표준 API는 다음과 같습니다.
Fetch API:
fetch()
: HTTP(S) 요청을 수행하기 위한 전역 함수.Request
: HTTP 요청을 나타냅니다.Response
: HTTP 응답을 나타냅니다.Headers
: HTTP 헤더를 나타냅니다.
URL API:
URL
: URL 구문 분석 및 조작용.URLSearchParams
: URL 쿼리 매개변수 작업용.
Streams API:
ReadableStream
: 비동기적으로 읽을 수 있는 데이터 소스를 나타냅니다. 요청/응답 본문, 파일 읽기 등에 사용됩니다.WritableStream
: 비동기적으로 쓸 수 있는 데이터 대상을 나타냅니다. 요청 본문, 파일 쓰기 등에 사용됩니다.TransformStream
: 데이터를 통과하면서 변환하는 이중 스트림(예: 압축, 인코딩).
Encoding API:
TextEncoder
: 문자열을Uint8Array
로 인코딩합니다(일반적으로 UTF-8).TextDecoder
:Uint8Array
를 문자열로 디코딩합니다.
Blob API:
Blob
: 불변의 원시 데이터를 나타내며, 종종 파일과 유사한 객체에 사용됩니다.File
: 이름 및 최종 수정 날짜와 같은 메타데이터를 포함하여 파일을 나타내기 위해Blob
을 확장합니다. (종종Bun.file().slice()
또는 폼 데이터에서 생성됩니다).
FormData API:
FormData
: 키/값 쌍 세트를 구축하는 데 사용되며, 종종fetch
요청에서 폼 데이터를 제출하는 데 사용됩니다.
WebSocket API:
WebSocket
: WebSocket 연결을 설정하기 위한 클라이언트 측 API. (서버 측 처리는Bun.serve
에 통합되어 있습니다).
Timers:
setTimeout
,setInterval
,clearTimeout
,clearInterval
: 코드 실행을 예약하기 위한 표준 함수.
Console API:
console.log
,console.error
,console.warn
등: 표준 로깅 함수.
Crypto API:
crypto.subtle
: 저수준 암호화 기본 요소(해싱, 서명, 암호화)에 대한 액세스를 제공합니다.crypto.randomUUID()
: v4 UUID를 생성합니다.crypto.getRandomValues()
: 암호학적으로 강력한 난수를 생성합니다.
Performance API:
performance.now()
: 성능 측정을 위한 고해상도 타임스탬프를 제공합니다.
이러한 필수 웹 API의 강력하고 성능이 뛰어난 구현을 제공함으로써 Bun은 익숙하고 표준화된 인터페이스를 사용하여 웹 서버, API 및 기타 네트워크 중심 애플리케이션을 구축하는 데 적합한 현대적인 런타임으로 자리매김합니다.
Bun HTTP 서버 설명
Bun에서 웹 서버를 생성하는 기본 방법은 Bun.serve
API를 통하는 것입니다. 이 API는 탁월한 성능과 사용 편의성을 위해 설계되었으며, Request
, Response
, fetch
와 같은 표준 웹 API와 원활하게 통합됩니다.
핵심 개념:
Bun.serve
함수는 구성 객체를 받고 Server
객체를 반환합니다. 구성의 가장 중요한 부분은 fetch
함수입니다.
import { type Server } from "bun";
const server: Server = Bun.serve({
port: 8080, // 수신 대기할 포트
hostname: "0.0.0.0", // 바인딩할 네트워크 인터페이스 (모두에 대해 0.0.0.0)
// fetch: 서버의 핵심 - 들어오는 요청 처리
async fetch(req: Request, server: Server): Promise<Response> {
// req는 표준 웹 API Request 객체입니다.
// server는 Server 인스턴스 자체에 대한 참조입니다.
const url = new URL(req.url);
// 기본 라우팅 예시
if (url.pathname === "/") {
return new Response("Homepage");
}
if (url.pathname === "/about") {
return new Response("About Us page");
}
if (url.pathname === "/greet" && req.method === "GET") {
const name = url.searchParams.get("name") || "World";
return new Response(`Hello, ${name}!`);
}
if (url.pathname === "/data" && req.method === "POST") {
try {
const data = await req.json(); // 요청 본문을 JSON으로 읽기
console.log("Received data:", data);
return new Response(JSON.stringify({ received: data }), {
headers: { 'Content-Type': 'application/json' }
});
} catch (e) {
return new Response("Invalid JSON body", { status: 400 });
}
}
// 기본 404 찾을 수 없음
return new Response("Page Not Found", { status: 404 });
},
// error: fetch 핸들러 *외부*에서 발생하는 오류에 대한 선택적 핸들러
error(error: Error): Response | Promise<Response> {
console.error("[Server Error]", error);
return new Response("Something went wrong!", { status: 500 });
},
// development: 유용한 개발 오류 페이지를 위해 true로 설정 (기본값: !process.env.NODE_ENV=production)
development: true,
// 고급 사용 사례를 위한 'websocket', 'tls'와 같은 기타 옵션이 있습니다.
});
console.log(`Bun server listening on http://${server.hostname}:${server.port}`);
// server 객체와 상호 작용할 수 있습니다.
// server.stop() // 서버 중지
// server.reload({...}) // 서버 구성 동적 업데이트 (예: fetch 핸들러)
주요 기능:
- 성능:
Bun.serve
는 Zig로 작성된 Bun의 사용자 정의 고도로 최적화된 HTTP 서버 구현을 기반으로 구축되었습니다. 많은 Node.js 프레임워크에 비해 낮은 지연 시간과 리소스 소비로 초당 매우 많은 수의 요청을 처리할 수 있습니다. fetch
핸들러: 표준(Request) => Response | Promise<Response>
시그니처를 사용하면 서비스 워커, Cloudflare Workers 또는 기타 최신 웹 프레임워크를 사용해 본 사람에게 핵심 로직이 익숙해집니다. 표준Request
및Response
객체 사용을 권장합니다.- Request 객체:
req
매개변수는 표준Request
속성 및 메서드에 대한 액세스를 제공합니다:req.url
,req.method
,req.headers
,req.json()
,req.text()
,req.arrayBuffer()
,req.formData()
,req.body
(ReadableStream
). - Response 객체: 표준
Response
객체를 생성하고 반환하여 본문(문자열, Buffer, Blob, Stream 등), 상태 코드 및 헤더를 쉽게 설정할 수 있습니다. - 오류 처리: 선택적
error
함수는 서버 자체에서 요청의 초기 처리 이전 또는 도중 발생하는 오류(예: TLS 핸드셰이크 실패, 잘못된 형식의 요청) 또는fetch
핸들러의try...catch
외부에서 동기적으로 발생하는 오류를 포착하는 중앙 집중식 장소를 제공합니다. 비동기fetch
핸들러 내부의 오류는 일반적으로 해당 위치에서 포착해야 합니다. - 스트리밍: 요청 및 응답 본문은 모두 표준
ReadableStream
및WritableStream
API를 사용하여 스트리밍할 수 있으며, 이는 대용량 업로드 또는 다운로드를 효율적으로 처리하는 데 필수적입니다. - 동적 재로드:
server.reload()
메서드를 사용하면 전체 서버 재시작 없이fetch
및error
핸들러를 포함한 서버 옵션을 업데이트할 수 있으며, 이는 HMR(Hot Module Replacement) 설정에 유용합니다.
Bun.serve
는 Bun에서 웹 애플리케이션 및 API를 구축하기 위한 강력하면서도 간단한 기반을 제공하며, 속도와 웹 표준 준수를 우선시합니다.
Bun Fetch 클라이언트
서버 API를 보완하기 위해 Bun은 외부 HTTP(S) 요청을 수행하기 위한 전역 fetch
함수를 제공합니다. 이 구현은 WHATWG Fetch 표준을 밀접하게 준수하여 웹 개발자에게 익숙하고 Bun.serve
내에서 사용되는 fetch
함수와의 일관성을 보장합니다. Bun의 네이티브 구현은 클라이언트 측 네트워킹 작업에 대한 고성능을 보장합니다.
요청 수행:
기본 사용법은 URL과 선택적으로 구성 객체를 사용하여 fetch
를 호출하는 것입니다.
async function makeRequests() {
const url = "https://httpbin.org"; // HTTP 요청 테스트에 유용한 서비스
// --- 기본 GET 요청 ---
console.log("--- GET Request ---");
try {
const getResponse = await fetch(`${url}/get?param1=value1`);
console.log(`Status: ${getResponse.status} ${getResponse.statusText}`);
// 요청이 성공했는지 확인 (상태 200-299)
if (!getResponse.ok) {
throw new Error(`HTTP error! status: ${getResponse.status}`);
}
// 헤더 액세스
console.log("Content-Type Header:", getResponse.headers.get('content-type'));
// 응답 본문을 JSON으로 읽기
const getData = await getResponse.json();
console.log("Response JSON:", getData.args); // httpbin.org/get은 쿼리 매개변수를 'args'로 반환합니다.
} catch (error) {
console.error("GET request failed:", error);
}
// --- JSON 본문이 있는 POST 요청 ---
console.log("\n--- POST Request (JSON) ---");
try {
const postData = { name: "Bun", type: "Runtime" };
const postResponse = await fetch(`${url}/post`, {
method: "POST",
headers: {
// JSON을 보내고 있음을 나타냅니다.
"Content-Type": "application/json",
"Accept": "application/json", // JSON을 다시 받기를 선호함을 나타냅니다.
"X-Custom-Header": "BunFetchExample",
},
// 본문은 JSON을 위해 문자열화되어야 합니다.
body: JSON.stringify(postData),
});
if (!postResponse.ok) {
throw new Error(`HTTP error! status: ${postResponse.status}`);
}
const postResult = await postResponse.json();
console.log("POST Response JSON:", postResult.json); // httpbin.org/post는 게시된 JSON을 'json'으로 반환합니다.
} catch (error) {
console.error("POST request failed:", error);
}
// --- 시간 제한이 있는 요청 ---
console.log("\n--- GET Request with Timeout ---");
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 2000); // 2초 후 중단
const timeoutResponse = await fetch(`${url}/delay/5`, { // 이 엔드포인트는 5초를 기다립니다.
signal: controller.signal // AbortSignal 전달
});
clearTimeout(timeoutId); // fetch가 더 빨리 완료되면 시간 제한 해제
console.log("Timeout request succeeded (unexpected for /delay/5)");
} catch (error: any) {
// 신호가 중단되면 AbortError가 발생합니다.
if (error.name === 'AbortError') {
console.log("예상대로 시간 제한으로 인해 Fetch가 중단되었습니다.");
} else {
console.error("Timeout request failed:", error);
}
}
}
await makeRequests();
주요 기능 및 옵션:
표준 API: 익숙한 fetch(url, options)
시그니처를 사용합니다.
메서드: 모든 표준 HTTP 메서드(GET
, POST
, PUT
, DELETE
, PATCH
, HEAD
, OPTIONS
)를 지원합니다. method
옵션을 통해 지정됩니다.
헤더: 헤더는 headers
옵션을 사용하여 설정되며, 이는 Headers
객체 또는 간단한 키-값 일반 객체일 수 있습니다.
요청 본문: body
옵션은 다양한 타입을 허용합니다.
string
: 텍스트로 전송됩니다 (JSON, XML, 일반 텍스트에 일반적).ArrayBuffer
/TypedArray
: 이진 데이터로 전송됩니다.Blob
/File
: 이진 데이터로 전송되며, 종종 적절한Content-Type
과 함께 사용됩니다.ReadableStream
: 본문 콘텐츠를 스트리밍하며, 대용량 업로드에 적합합니다.URLSearchParams
: 자동으로Content-Type
을application/x-www-form-urlencoded
로 설정합니다.FormData
: 자동으로Content-Type
을multipart/form-data
로 설정합니다.
응답 처리: fetch
호출은 Response
객체로 해결되는 Promise
를 반환합니다.
response.ok
: 성공적인 HTTP 상태(200-299)를 나타내는 부울.response.status
: HTTP 상태 코드 (예: 200, 404).response.statusText
: HTTP 상태 메시지 (예: "OK", "Not Found").response.headers
: 응답 헤더에 액세스하기 위한Headers
객체.- 본문 읽기 메서드:
response.json()
,response.text()
,response.arrayBuffer()
,response.blob()
,response.formData()
. 이들은 Promise를 반환합니다. response.body
: 응답 본문을 스트리밍하기 위한ReadableStream
.
시간 제한 및 취소: AbortController
및 AbortSignal
을 사용하여 시간 제한을 구현하거나 요청을 수동으로 취소합니다. signal
을 fetch
옵션에 전달합니다.
리다이렉트: redirect
옵션('follow'
, 'manual'
, 'error'
)으로 제어됩니다. 기본값은 'follow'
입니다.
- 캐싱:
cache
옵션(예:'no-store'
,'reload'
)으로 제어됩니다.
Bun의 fetch
는 HTTP 리소스와 상호 작용하는 성능이 뛰어나고 표준을 준수하는 방법을 제공하며, Bun 생태계에 원활하게 통합됩니다.
Bun 웹소켓
웹소켓은 단일 TCP 연결을 통해 클라이언트와 서버 간에 지속적이고 양방향 통신 채널을 설정하는 방법을 제공합니다. Bun은 웹소켓 클라이언트 생성과 Bun.serve
내에서 서버 측 웹소켓 연결 처리를 위한 뛰어난 지원을 제공합니다.
1. 웹소켓 클라이언트:
Bun은 클라이언트 연결을 생성하기 위한 표준 브라우저 WebSocket
API를 구현합니다.
// websocket-client.ts
const wsUrl = "wss://ws.postman-echo.com/raw"; // 공개 에코 서버
console.log(`클라이언트를 ${wsUrl}에 연결 중...`);
const socket = new WebSocket(wsUrl);
// 이벤트: 연결이 성공적으로 열림
socket.addEventListener("open", (event) => {
console.log("[클라이언트] 웹소켓 연결이 설정되었습니다!");
socket.send("Bun 클라이언트에서 안녕하세요!");
// 짧은 지연 후 이진 데이터 전송
setTimeout(() => {
const binaryData = new TextEncoder().encode("Bun 이진 데이터");
console.log("[클라이언트] 이진 데이터 전송:", binaryData);
socket.send(binaryData);
}, 500);
// 일정 시간 후 연결 닫기
setTimeout(() => {
console.log("[클라이언트] 연결 닫는 중...");
socket.close(1000, "클라이언트 테스트 완료"); // 1000 = 정상 종료
}, 2000);
});
// 이벤트: 서버에서 메시지 수신
socket.addEventListener("message", async (event) => {
// event.data는 문자열, Blob 또는 ArrayBuffer일 수 있습니다.
let messageContent: string | Uint8Array;
if (typeof event.data === "string") {
messageContent = event.data;
console.log(`[클라이언트] 문자열 수신: "${messageContent}"`);
} else if (event.data instanceof Blob) {
// Bun은 종종 웹소켓 API에서 Blob으로 이진 데이터를 수신합니다.
const arrayBuffer = await event.data.arrayBuffer();
messageContent = new Uint8Array(arrayBuffer);
console.log(`[클라이언트] 이진 데이터 수신 (Blob):`, messageContent, `(${new TextDecoder().decode(messageContent)})`);
} else if (event.data instanceof ArrayBuffer) {
messageContent = new Uint8Array(event.data);
console.log(`[클라이언트] 이진 데이터 수신 (ArrayBuffer):`, messageContent, `(${new TextDecoder().decode(messageContent)})`);
} else {
console.log("[클라이언트] 알 수 없는 메시지 타입 수신:", event.data);
}
});
// 이벤트: 오류 발생 (네트워크 문제 등)
socket.addEventListener("error", (event) => {
// 이벤트 객체는 종종 특정 세부 정보가 부족합니다. 콘솔/네트워크 로그를 확인하십시오.
console.error("[클라이언트] 웹소켓 오류:", event.type);
});
// 이벤트: 연결이 닫힘
socket.addEventListener("close", (event) => {
console.log(
`[클라이언트] 웹소켓 닫힘. 코드: ${event.code}, 이유: "${event.reason}", 정상 종료: ${event.wasClean}`
);
// 소켓이 닫히면 스크립트를 깨끗하게 종료합니다.
process.exit(0);
});
// 이벤트 처리를 위해 잠시 유지하고, 종료는 'close' 리스너에서 처리됩니다.
// setInterval(() => {}, 1000);
bun run websocket-client.ts
로 실행합니다. 에코 서버에 연결하고, 메시지를 보내고, 다시 받고, 연결을 닫습니다.
2. 웹소켓 서버 (Bun.serve
통합):
서버에서 웹소켓 연결 처리는 Bun.serve
구성 객체에 websocket
속성을 추가하여 수행됩니다. 이 속성에는 다양한 웹소켓 수명 주기 이벤트에 대한 핸들러 함수가 포함됩니다.
// websocket-server.ts
import { type ServerWebSocket, type WebSocketHandler } from "bun";
console.log("웹소켓 서버 시작 중...");
// 웹소켓 핸들러 객체 정의
const wsHandler: WebSocketHandler<{ authToken: string }> = {
// open(ws): 새 웹소켓 연결이 설정될 때 호출됩니다.
// 'fetch'에서 server.upgrade() 호출이 먼저 필요합니다.
open(ws: ServerWebSocket<{ authToken: string }>) {
console.log(`[서버] 연결 열림. 토큰: ${ws.data.authToken}`);
ws.send("Bun 웹소켓 서버에 오신 것을 환영합니다!");
// pub/sub 토픽 구독
ws.subscribe("the-group-chat");
// 토픽에 메시지 게시 (새 사용자 포함)
ws.publish("the-group-chat", `토큰 ${ws.data.authToken}을 가진 사용자가 참여했습니다.`);
},
// message(ws, message): 클라이언트로부터 메시지가 수신될 때 호출됩니다.
// 'message'는 문자열 또는 Uint8Array(Buffer)일 수 있습니다.
message(ws: ServerWebSocket<{ authToken: string }>, message: string | Buffer) {
const messageString = message.toString(); // 문자열/버퍼 모두 처리
console.log(`[서버] 토큰 ${ws.data.authToken}으로부터 수신: ${messageString}`);
// 토큰을 앞에 붙여 메시지를 다시 에코합니다.
// ws.send(`[${ws.data.authToken}] 당신이 보낸 메시지: ${messageString}`);
// 채팅방의 모든 사람에게 메시지 게시 (보낸 사람 포함)
server.publish("the-group-chat", `[${ws.data.authToken}] ${messageString}`);
},
// close(ws, code, reason): 웹소켓 연결이 닫힐 때 호출됩니다.
close(ws: ServerWebSocket<{ authToken: string }>, code: number, reason: string) {
const goodbyeMessage = `[서버] 연결 닫힘. 토큰: ${ws.data.authToken}, 코드: ${code}, 이유: ${reason}`;
console.log(goodbyeMessage);
// 구독 취소 및 다른 사람에게 알림
ws.unsubscribe("the-group-chat");
server.publish("the-group-chat", `토큰 ${ws.data.authToken}을 가진 사용자가 떠났습니다.`);
},
// drain(ws): 선택 사항. 소켓의 버퍼링된 양이 감소할 때 호출되며,
// 백프레셔 후 더 많은 데이터를 수신할 준비가 되었음을 나타냅니다.
// 대용량 데이터를 전송할 때 흐름 제어를 관리하는 데 유용합니다.
// drain(ws: ServerWebSocket<{ authToken: string }>) {
// console.log(`[서버] 토큰 ${ws.data.authToken}에 대한 드레인 이벤트`);
// },
};
// 웹소켓 처리가 포함된 HTTP 서버 생성
const server = Bun.serve<{ authToken: string }>({ // ws.data 타입에 대한 제네릭 전달
port: 8081,
// fetch 핸들러는 HTTP -> 웹소켓 업그레이드 요청을 처리해야 합니다.
fetch(req: Request, server: Server): Response | undefined {
const url = new URL(req.url);
// 요청이 웹소켓으로 업그레이드하려는지 확인
if (url.pathname === "/ws") {
// 웹소켓 컨텍스트에 전달할 일부 데이터 (예: 인증 토큰) 추출
const token = req.headers.get("sec-websocket-protocol") || "anonymous"; // 예시: 토큰에 프로토콜 헤더 사용
const success = server.upgrade(req, {
// data 객체는 이 연결에 대한 모든 웹소켓 핸들러에서 사용할 수 있는
// ws 인스턴스 (ws.data)에 첨부됩니다.
// 나중에 워커/프로세스 간에 사용하려면 JSON 직렬화 가능해야 합니다.
data: {
authToken: token,
},
// headers: new Headers({ 'X-Custom-Response-Header': 'UpgradeValue' }) // 선택 사항: 101 응답에 헤더 추가
});
if (success) {
// server.upgrade()는 101 Switching Protocols 응답을 처리합니다.
// 성공적인 업그레이드 후 fetch 핸들러에서 아무것도 반환하지 않습니다.
return undefined;
} else {
// 업그레이드 실패 (예: 잘못된 요청 헤더)
return new Response("웹소켓 업그레이드 실패", { status: 400 });
}
}
// 다른 경로에서 일반 HTTP 요청 처리
return new Response("웹소켓 엔드포인트가 아닙니다. /ws를 시도하십시오.", { status: 404 });
},
// 웹소켓 핸들러 객체 첨부
websocket: wsHandler,
error(error: Error): Response | Promise<Response> {
console.error("[서버 오류]", error);
return new Response("서버 오류", { status: 500 });
},
});
console.log(`Bun 웹소켓 서버가 ws://localhost:${server.port}/ws에서 수신 대기 중입니다.`);
서버 핵심 개념:
업그레이드 요청: 웹소켓 연결은 특정 헤더(Upgrade: websocket
, Connection: Upgrade
, Sec-WebSocket-Key
등)가 있는 표준 HTTP GET 요청으로 시작합니다. fetch
핸들러는 이러한 요청을 감지해야 합니다.
server.upgrade(req, { data: ... })
:fetch
핸들러 내에서 호출되는 이 중요한 메서드는 웹소켓 핸드셰이크를 완료하려고 시도합니다. 성공하면true
를 반환하고 Bun은websocket
핸들러를 사용하여 연결을 인계받습니다. 실패하면false
를 반환합니다. 성공적인 업그레이드 후fetch
에서undefined
를 반환해야 합니다.websocket
핸들러 객체: 연결된 클라이언트에 대한 웹소켓 수명 주기를 관리하는open
,message
,close
및drain
함수를 포함합니다.ServerWebSocket<T>
: 서버 측 웹소켓 연결을 나타내는 타입입니다. 제네릭T
는ws.data
객체의 타입을 정의합니다.ws.data
: 각 연결과 연결된 객체로,server.upgrade
옵션의data
속성에 의해 초기화됩니다. 연결별 상태(예: 사용자 ID, 인증 토큰)를 저장하는 데 유용합니다.
Pub/Sub: Bun에는 웹소켓을 위한 내장된 효율적인 게시/구독 기능이 포함되어 있습니다.
ws.subscribe("topic-name")
: 연결을 토픽에 구독합니다.ws.unsubscribe("topic-name")
: 연결 구독을 취소합니다.ws.publish("topic-name", message)
: 해당 토픽에 구독된 모든 연결에 메시지를 보내지만, 보낸 사람ws
는 제외합니다.server.publish("topic-name", message)
: 해당 토픽에 구독된 모든 연결에 메시지를 보냅니다(시스템 전체 브로드캐스트에 유용).
백프레셔: ws.send()
메서드는 버퍼링된 바이트 수를 반환합니다. 이 값이 커지면 클라이언트가 수신할 수 있는 속도보다 빠르게 보내고 있을 수 있습니다. drain
이벤트는 버퍼가 줄어들었음을 알려주므로 안전하게 전송을 재개할 수 있습니다.
Bun의 통합 웹소켓 지원은 내장된 pub/sub 기능을 갖춘 애플리케이션에 실시간 기능을 구축하는 성능이 뛰어나고 편리한 방법을 제공합니다.
이 가이드에서는 Bun의 핵심 철학과 설치부터 Bun.serve
, Bun.file
, Bun.build
와 같은 특정 API, 그리고 fetch
및 WebSocket
과 같은 중요한 웹 표준 구현에 이르기까지 Bun의 기본 측면을 다루었습니다. 속도, 통합 도구, 네이티브 TypeScript/JSX 지원 및 표준에 대한 집중을 결합하여 Bun은 현대적인 JavaScript 및 TypeScript 개발을 위한 매력적이고 생산적인 환경을 제공합니다.
개발팀이 최대한의 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하시나요?
Apidog는 여러분의 모든 요구를 충족하며, 훨씬 저렴한 가격으로 Postman을 대체합니다!