오늘도 공부
Postman 대안을 찾는다면, Bruno를 봐야 하는 이유 본문
https://www.usebruno.com
Bruno - The Git-Native API Client
Bruno is the Git-native API client for REST, GraphQL, gRPC and Websocket. A local and open-source solution to Postman. Fast, developer-first, and no cloud syncing.
www.usebruno.com
API 클라이언트를 다시 “개발자 도구”로 되돌리는 로컬-퍼스트 접근
클라우드 계정을 만들고, 워크스페이스를 공유하고, 벤더가 정한 방식으로 협업하는 API 툴에 익숙해져 있다면 Bruno는 꽤 낯설게 느껴진다. Bruno는 더 많은 플랫폼 기능을 얹는 대신, 오히려 반대로 간다. “API Client, not a Platform”이라는 메시지처럼 Bruno는 API 테스트 도구를 다시 로컬 파일, Git, 텍스트 기반 워크플로우로 되돌리려는 프로젝트다. 공식 사이트와 문서는 Bruno를 Git-friendly, offline-first, open-source API client로 설명하며, 컬렉션을 로컬 폴더와 .bru 텍스트 파일로 저장하고 클라우드 동기화를 기본 전제로 두지 않는다고 밝히고 있다. 저장소 기준으로도 Bruno는 MIT 라이선스 오픈소스이며, 2026년 3월 기준 GitHub에서 4만 개가 넘는 스타를 모으고 있다. (Bruno)
많은 개발자가 Bruno를 “Postman 대체재”로 소개하지만, 정확히 말하면 Bruno의 핵심은 단순한 대체가 아니다. Bruno는 API 요청을 더 화려하게 다루는 플랫폼이 아니라, API 컬렉션을 소스 코드처럼 버전 관리하고 리뷰하고 자동화하려는 개발팀에 맞춘 도구다. 지원 범위도 생각보다 넓다. 공식 문서 기준으로 REST, GraphQL, SOAP, gRPC, WebSocket 요청을 다룰 수 있고, 테스트/스크립트, 변수, 비밀값 관리, OpenAPI 가져오기, CLI 실행, VS Code 확장까지 제공한다. (Bruno Docs)
Bruno는 어떤 프로젝트인가
Bruno는 로컬 파일 시스템에 API 컬렉션을 저장하는 오픈소스 API 클라이언트다. 공식 저장소는 “Postman/Insomnia의 가벼운 대안”이라고 소개하지만, 실제로는 “가벼움”보다 “소유권”이 더 중요한 키워드다. 요청, 환경, 테스트 정보가 별도 SaaS 워크스페이스에 갇히는 것이 아니라 프로젝트 디렉터리 안에 텍스트 파일로 남는다. 이 철학은 Bruno 공식 문서가 강조하는 두 가지 문제, 즉 협업과 데이터 프라이버시를 직접 겨냥한다. (GitHub)
프로젝트의 상표와 저작권 표기에서는 Anoop M D와 기여자들이 명시되어 있고, 라이선스는 MIT다. 저장소 언어 비중을 보면 JavaScript가 가장 크고 TypeScript가 그 뒤를 잇는다. 즉, 이 도구는 폐쇄적인 데스크톱 유틸리티라기보다 활발하게 진화하는 개발자 생태계형 오픈소스에 가깝다. (GitHub)
왜 이 프로젝트가 등장했을까
여기서 Bruno를 이해하는 핵심은 기능 목록이 아니라 문제 정의다.
기존 API 클라이언트는 점점 더 “플랫폼화”되는 경향이 있다. 로그인, 클라우드 동기화, 팀 워크스페이스, 자체 공유 포맷, SaaS 중심 협업 모델이 기본값이 된다. 이 접근은 분명 편리하지만, 개발팀 입장에서는 몇 가지 불편이 생긴다.
첫째, API 컬렉션이 Git 바깥으로 밀려난다. 코드 리뷰는 GitHub나 GitLab에서 하는데, API 요청 정의와 테스트는 다른 SaaS 안에 있다. 그러면 실제 서비스 코드와 API 테스트 자산이 서로 다른 진실의 원천이 된다. Bruno 팀도 공식 블로그에서 “Git이 소프트웨어 개발의 기반”이며 API 테스트와 문서를 Git 밖에 두면 드리프트와 사일로가 생긴다고 지적한다. (Bruno Blog)
둘째, 협업이 쉬워 보이지만 개발자다운 협업은 오히려 어려워질 수 있다. 개발자에게 익숙한 협업은 브랜치, 커밋, diff, PR, merge다. 그런데 API 도구가 자체 협업 모델을 강제하면, “컬렉션 편집”은 쉬워져도 “소프트웨어 변경과 함께 움직이는 API 변경”은 덜 투명해진다. Bruno는 이 문제를 컬렉션을 그냥 폴더와 파일로 저장하는 방식으로 풀었다. (Bruno Docs)
셋째, 보안과 프라이버시 이슈다. 공식 문서는 기존 API 클라이언트들이 이름, 이메일 같은 PII는 물론 요청/응답 내용, 키, 토큰까지 수집 가능한 구조로 흘러갔다고 비판한다. Bruno는 로그인 개념과 기본 클라우드 동기화가 없고, 작업 데이터는 로컬에 남는다고 설명한다. (Bruno Docs)
즉 Bruno는 단순히 “Postman보다 가벼운 앱”이 아니라, API 자산을 다시 개발 워크플로우 안으로 끌어오는 프로젝트라고 보는 편이 맞다.
Bruno의 핵심 철학: API도 코드처럼 관리한다
Bruno를 한 문장으로 요약하면 이렇다.
API 요청, 테스트, 환경 설정을 GUI 데이터가 아니라 파일로 다루는 API 클라이언트
이게 왜 중요한지 개발자 관점에서 보면 바로 이해된다.
예를 들어 보자. 어떤 팀이 get-user, create-order, cancel-order 요청을 운영 중이라고 하자. Bruno에서는 이런 컬렉션이 실제 디렉터리 구조로 존재한다.
orders/
get-user.bru
create-order.bru
cancel-order.bru
environments/
local.bru
staging.bru
이 구조의 의미는 단순 저장 형식이 아니다.
- Git diff가 된다
- PR에서 리뷰가 된다
- 브랜치별 실험이 된다
- 서비스 코드와 함께 버전이 맞춰진다
- CI에서 같은 컬렉션을 실행할 수 있다
즉 API 클라이언트 결과물이 “툴 안의 데이터”가 아니라 “저장소 안의 자산”이 된다. 공식 문서도 Bruno 컬렉션이 파일 시스템에 직접 저장되고, Bru라는 plain text markup language로 요청을 표현한다고 설명한다. (GitHub)
핵심 기능 1: .bru 파일 기반 컬렉션
Bruno의 가장 큰 차별점은 .bru 포맷이다. JSON export를 따로 뽑는 방식이 아니라, 처음부터 요청이 텍스트 파일이다. 공식 샘플은 다음처럼 매우 단순한 구조를 보여준다. (Bruno Docs)
get {
url: https://api.github.com/users/usebruno
}
조금 더 실무적으로 바꾸면 이런 식으로 쓸 수 있다.
meta {
name: Get User
type: http
seq: 1
}
get {
url: {{baseUrl}}/users/{{userId}}
}
headers {
Authorization: Bearer {{accessToken}}
Accept: application/json
}
tests {
test("status is 200", function() {
expect(res.getStatus()).to.equal(200);
});
}
이 포맷의 장점은 사람이 읽기 쉽고, Git diff가 비교적 명확하다는 점이다. YAML이나 JSON보다 DSL이 낫냐는 논쟁은 있을 수 있지만, Bruno 팀은 별도 Bru 언어를 통해 요청 구조를 간결하게 표현하려고 했다. 결과적으로 API 요청을 “도구 내부 상태”가 아니라 “리뷰 가능한 텍스트”로 만든 것이 핵심이다. (Bruno Docs)
핵심 기능 2: Git 중심 협업
Bruno의 진짜 강점은 팀 개발에서 드러난다.
보통 API 변경은 다음 흐름을 탄다.
- 백엔드 코드 수정
- OpenAPI 또는 라우트 변경
- API 테스트 수정
- 문서 수정
문제는 이 네 단계가 서로 다른 시스템에 흩어져 있으면 리뷰가 끊긴다는 점이다. Bruno는 컬렉션이 리포지토리에 있으므로 코드 변경과 API 테스트 변경을 한 PR 안에서 함께 다룰 수 있다. 공식 사이트와 문서도 “Collections stored as code”, “Works with Git”, “Collaboration via Git”를 전면에 내세운다. (Bruno)
예를 들어 주문 생성 API가 바뀌는 PR에서 다음을 같이 리뷰할 수 있다.
post {
- url: {{baseUrl}}/orders
+ url: {{baseUrl}}/v2/orders
}
body:json {
{
"productId": "{{productId}}",
- "quantity": 1
+ "quantity": 1,
+ "currency": "KRW"
}
}
이런 diff는 “API가 어떻게 바뀌었는지”를 코드 리뷰 문맥 안에서 그대로 보여준다. SaaS 워크스페이스 안에서 바뀐 컬렉션보다, 개발자에겐 이 방식이 훨씬 추적 가능하다.
핵심 기능 3: 테스트와 스크립트
Bruno는 단순 요청 전송 툴이 아니다. 공식 문서에 따르면 pre-request와 post-response 단계에서 JavaScript를 실행할 수 있고, req, res, bru 객체를 통해 요청과 응답, 환경변수를 제어할 수 있다. 응답 시간, 크기, 상태 코드 같은 값도 테스트에서 다룰 수 있다. (Bruno Docs)
예를 들어 토큰을 동적으로 세팅하고 응답을 검증하는 흐름은 이런 식으로 구성할 수 있다.
meta {
name: Create Order
type: http
seq: 2
}
post {
url: {{baseUrl}}/orders
}
headers {
Authorization: Bearer {{accessToken}}
Content-Type: application/json
}
body:json {
{
"productId": "{{productId}}",
"quantity": 2
}
}
script:pre-request {
const traceId = `trace-${Date.now()}`;
req.setHeader("X-Trace-Id", traceId);
bru.setEnvVar("lastTraceId", traceId);
}
tests {
test("status is 201", function() {
expect(res.getStatus()).to.equal(201);
});
test("response time under 1000ms", function() {
expect(res.getResponseTime()).to.be.lessThan(1000);
});
test("has order id", function() {
const data = res.getBody();
expect(data.id).to.exist;
});
}
즉 Bruno는 “요청 보내는 앱”에서 끝나는 게 아니라, API 검증 흐름을 코드화하는 도구로도 쓸 수 있다.
핵심 기능 4: CLI와 CI/CD 연결
로컬 GUI에서 잘 되던 API 테스트가 CI에서 재현되지 않는 경험은 흔하다. Bruno는 이 지점을 CLI로 메운다. 공식 CLI 문서에 따르면 bru run으로 컬렉션이나 특정 요청을 실행할 수 있고, 환경 지정, 결과 출력, 인증서 옵션, OpenAPI import까지 지원한다. (GitHub)
가장 기본적인 실행은 이렇다.
npm install -g @usebruno/cli
bru run
특정 환경으로 컬렉션을 실행할 수도 있다.
bru run orders --env staging --output results.json
이 말은 곧, 로컬에서 작성한 .bru 컬렉션을 CI 파이프라인에서 그대로 돌릴 수 있다는 뜻이다.
name: API Regression Test
on:
pull_request:
branches: [ main ]
jobs:
bruno-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install -g @usebruno/cli
- run: bru run collections/orders --env-file ./collections/orders/environments/staging.bru
이 구조는 특히 백엔드 팀, 플랫폼 팀, QA 자동화 팀에 잘 맞는다. GUI 전용 도구가 아니라 저장소 기반 테스트 자산이 되기 때문이다.
핵심 기능 5: 비밀값과 환경 관리
“파일 기반”이라고 하면 가장 먼저 떠오르는 우려가 있다.
그럼 토큰이나 API 키도 Git에 올라가는 것 아닌가?
Bruno는 이 지점을 꽤 현실적으로 다룬다. 공식 문서에 따르면 secret 변수는 로컬 머신에 저장되며, 가능한 경우 OS 레벨 암호화를 사용하고 그렇지 않으면 AES-256으로 암호화된다. 또 .env 파일을 이용한 방식도 지원한다. 상위 플랜에서는 AWS Secrets Manager, Azure Key Vault, HashiCorp Vault와의 연동도 제공한다. 보고서에서는 secret masking도 지원한다. (Bruno Docs)
즉 Bruno의 설계는 “모든 걸 무조건 파일에 박아라”가 아니라, 버전 관리 가능한 정보와 비밀 정보의 경계를 분리하라에 가깝다.
실무적으로는 이런 식의 전략이 자연스럽다.
- collection.bru, 요청 파일, 일반 환경값은 Git에 포함
- 토큰/키는 secret 변수 또는 .env로 분리
- CI에서는 환경 파일 또는 secret manager로 주입
이 접근은 애플리케이션 코드에서 .env와 secret vault를 병행하는 패턴과 매우 닮아 있다.
핵심 기능 6: OpenAPI, VS Code, 멀티프로토콜 지원
Bruno는 “로컬 파일 기반”만 강조하면 자칫 단순해 보일 수 있지만, 기능 범위는 꽤 넓다.
공식 문서 기준으로 Bruno는 REST, GraphQL, SOAP, gRPC, WebSocket을 지원하며, gRPC 스트리밍도 다룰 수 있다. 또 OpenAPI v3 파일을 가져와 Bruno 컬렉션으로 변환할 수 있고, CLI에서도 import가 가능하다. VS Code 확장도 제공해서 에디터 안에서 .bru 파일을 열고 요청을 보낼 수 있다. 컬렉션으로부터 standalone HTML 문서를 생성하는 기능도 있다. (Bruno Docs)
이건 꽤 중요하다. Bruno는 “단순하고 미니멀한 도구”이면서도, 실제로는 현대 API 팀이 기대하는 핵심 기능을 상당 부분 갖추고 있다.
프로젝트 아키텍처를 어떻게 이해하면 좋을까
Bruno는 사용자 입장에서 GUI 앱처럼 보이지만, 설계 관점에서는 몇 개의 층으로 나눠 이해하는 편이 좋다.
- 컬렉션 저장 계층
.bru 파일, 환경 파일, 폴더 구조가 저장소의 원본이 된다. - 파서/실행 계층
.bru 문서를 파싱하고, 변수/시크릿/스크립트를 해석해 실제 요청 실행 모델로 바꾼다. - 프로토콜 실행 계층
HTTP, GraphQL, SOAP, gRPC, WebSocket 요청을 실제로 보낸다. - 자동화 계층
CLI가 같은 컬렉션 자산을 읽어 CI/CD에서 실행한다. - 개발 환경 통합 계층
데스크톱 앱과 VS Code 확장이 같은 컬렉션 파일을 공유하며 동작한다.
이를 다이어그램으로 그리면 이런 구조로 볼 수 있다.

이 구조의 핵심은 UI가 원본이 아니라 파일이 원본이라는 점이다. 많은 API 툴은 내부 상태를 UI가 소유하고 export가 부가 기능이지만, Bruno는 반대로 파일이 원본이고 UI는 그 파일을 다루는 인터페이스다. 그래서 Git과 궁합이 좋다.
Bruno가 특히 잘 맞는 팀
Bruno는 모든 팀에 무조건 정답은 아니다. 하지만 아래 같은 상황에서는 매우 강하다.
1. 백엔드 팀이 API 변경을 코드와 함께 리뷰하고 싶을 때
서비스 코드 PR에 API 컬렉션 변경도 함께 넣고 싶다면 Bruno가 자연스럽다. 요청 정의가 파일이므로 코드 리뷰 흐름에 잘 붙는다. (Bruno Docs)
2. 보안/프라이버시 정책상 클라우드 동기화를 꺼리는 조직
금융, 공공, 엔터프라이즈 환경처럼 API 요청/응답 데이터가 외부 클라우드 워크스페이스에 남는 것을 불편해하는 경우, Bruno의 offline-first 철학은 꽤 설득력이 있다. (Bruno Docs)
3. API 테스트를 CI/CD에 묶고 싶은 팀
GUI에서만 쓰는 수동 툴이 아니라, 컬렉션을 자동화 실행 자산으로 만들고 싶다면 Bruno CLI가 강점이 된다. (GitHub)
4. 개발자 도구를 Git 중심으로 통일하고 싶은 팀
코드, 인프라, 문서, API 테스트를 모두 저장소 중심으로 운영하려는 팀에게 Bruno는 철학적으로도 잘 맞는다.
Bruno가 덜 맞을 수 있는 경우
반대로 이런 경우에는 기대 조정이 필요하다.
1. 비개발자 중심 협업이 더 중요한 팀
파일, Git, 브랜치, PR보다 SaaS UI 기반 공유와 실시간 협업이 더 중요하면 Bruno의 장점이 덜 체감될 수 있다.
2. “플랫폼형” API 툴의 관리 기능이 핵심인 조직
대규모 중앙 관리, SaaS 기반 거버넌스, 비기술 조직과의 통합 워크플로우가 중요하면 다른 선택지가 더 잘 맞을 수 있다.
3. 툴이 아니라 워크스페이스를 원하는 경우
Bruno는 의도적으로 “플랫폼이 되지 않으려는” 도구다. 이 철학은 장점이자 동시에 한계다. 공식 사이트가 이를 아주 노골적으로 내세우는 이유도 여기에 있다. (Bruno)
실제 사용 예시: 서비스 저장소 안에 Bruno를 넣는 방식
아래처럼 프로젝트에 아예 Bruno 컬렉션을 포함시키면 꽤 실용적이다.
my-service/
src/
docs/
openapi/
schema.yaml
bruno/
collection.bru
users/
get-user.bru
create-user.bru
orders/
create-order.bru
environments/
local.bru
staging.bru
개발 흐름은 이렇게 갈 수 있다.
# 기능 브랜치 생성
git checkout -b feat/order-currency
# 백엔드 코드 수정
# OpenAPI 수정
# bruno/orders/create-order.bru 수정
# 로컬에서 Bruno GUI로 검증
# 또는 CLI로 검증
bru run bruno/orders --env-file bruno/environments/local.bru
그리고 PR에서는 이런 항목이 한 번에 리뷰된다.
- API 엔드포인트 변경
- 요청/응답 스키마 변경
- 관련 Bruno 테스트 추가
- 환경 변수 반영 여부
이게 Bruno의 본질이다.
API 테스트를 “별도 툴 작업”이 아니라 “저장소 변경의 일부”로 만든다.
Postman 대안이라는 표현만으로는 Bruno를 설명하기 어렵다
Bruno를 단순히 “Postman 대안”이라고만 소개하면 중요한 포인트를 놓친다.
Bruno의 핵심은 더 예쁜 UI나 더 많은 협업 기능이 아니다.
핵심은 다음 세 가지다.
첫째, API 자산의 소유권을 개발팀에게 돌려준다.
컬렉션이 로컬 파일이고 Git에 들어간다.
둘째, API 테스트를 소프트웨어 개발 프로세스 안으로 다시 편입시킨다.
코드와 함께 리뷰하고 브랜치 전략 안에서 움직인다.
셋째, 클라우드 플랫폼이 아닌 개발자 도구로 남으려 한다.
이 점이 Bruno를 독특하게 만든다. (Bruno)
마무리
Bruno는 “요청을 보내는 앱”이 아니다.
정확히는 API 컬렉션을 텍스트 파일로 만들고, 그것을 Git과 CI/CD에 연결해, API 작업을 개발자 워크플로우로 되돌리는 도구다.
그래서 Bruno가 잘 맞는 팀은 대체로 명확하다.
API를 많이 다루고, Git을 중심으로 협업하고, 테스트 자산을 코드처럼 관리하고 싶고, 가능하면 클라우드 종속을 줄이고 싶은 팀이다.
Postman의 대안을 찾고 있다면, Bruno를 “비슷한 툴 하나”로 보지 않는 편이 좋다.
오히려 이렇게 보는 게 더 정확하다.
Bruno는 API 클라이언트를 다시 개발자 소유의 로컬 자산으로 되돌리려는 시도다.
'AI' 카테고리의 다른 글
| GPT-5.4로 “매력적인 프론트엔드” 만드는 방법 (0) | 2026.03.23 |
|---|---|
| TradingAgents: 여러 에이전트로 동작되는 트레이딩 프레임워크 (0) | 2026.03.23 |
| Full-Stack AI Agent Template: 몇 주 걸릴 AI 제품 인프라를 몇 분 만에 뽑아내는 생성형 템플릿 (0) | 2026.03.20 |
| gstack: Claude Code를 ‘가상 엔지니어링 조직’으로 바꾸는 오픈소스 소프트웨어 팩토리 (0) | 2026.03.20 |
| Arnis: 현실 세계를 통째로 Minecraft로 옮기는 오픈소스, 내부 구조까지 뜯어보기 (0) | 2026.03.20 |
