Bruno
GitHub Overview
usebruno/bruno
Opensource IDE For Exploring and Testing API's (lightweight alternative to Postman/Insomnia)
Topics
Star History
Development Tool
Bruno
Overview
Bruno is a privacy-first open-source API client. Data is stored completely locally with Git-friendly JSON format for collection management. Following developer backlash against Postman's monetization, it has experienced rapid growth since 2023, particularly gaining support from developers who prioritize offline usage and privacy protection.
Details
Bruno was developed as an open-source IDE for API exploration and testing. Its greatest feature is the "privacy-first" design that operates completely offline and intentionally does not provide cloud sync functionality. While traditional API clients adopt cloud-based data storage, Bruno prioritizes keeping user data on local devices. For collection management, it uses a proprietary Bru format plain-text markup language, storing request information directly in filesystem folders. This design enables seamless integration with version control systems like Git, making diff viewing and merge operations easy in team development. The API request execution flow adopts a sophisticated architecture where UI, Redux store, IPC bridge, and main process work together, providing a comprehensive lifecycle that includes pre-request script and post-response test execution. It supports GraphQL, REST APIs, various authentication methods (Basic, Bearer, OAuth), and offers rich import functionality from Postman, OpenAPI, and Insomnia.
Advantages & Disadvantages
Advantages
- Complete Privacy Protection: Data never sent to cloud, stored locally only
- Full Git Support: Plain text format enables easy version control and diff viewing
- Open Source: Completely free with MIT license, customizable
- Lightweight & Fast: Electron-based but performance-focused design
- Migration Friendly: Easy import from Postman, Insomnia, OpenAPI
- Team Collaboration: Natural collaboration through Git
- Rich Features: GraphQL support, script execution, code generation, etc.
- Cross-platform: Available on Windows, macOS, Linux
Disadvantages
- No Cloud Sync: Intentional design choice not to provide cloud features
- Learning Curve: Requires understanding of Git integration and Bru format
- Small Ecosystem: Limited plugins and extensions compared to established tools
- Limited Enterprise Features: Team management and enterprise capabilities are limited
- Emerging Tool: Shorter history compared to Postman, may lack stability
Reference Links
- Bruno Official Site
- GitHub - usebruno/bruno
- Bruno Documentation
- Bruno vs Postman Comparison
- Bruno Downloads
Usage Examples
Basic REST Request (Bru Format)
meta {
name: Get User
type: http
seq: 1
}
get {
url: {{baseUrl}}/users/{{userId}}
}
headers {
Authorization: Bearer {{accessToken}}
Content-Type: application/json
}
vars {
userId: 12345
}
tests {
test("Status is 200", function() {
expect(res.status).to.equal(200);
});
test("User has email", function() {
expect(res.body.email).to.be.a('string');
});
}
POST Request with JSON Body
meta {
name: Create User
type: http
seq: 2
}
post {
url: {{baseUrl}}/users
}
headers {
Authorization: Bearer {{accessToken}}
Content-Type: application/json
}
body:json {
{
"name": "John Doe",
"email": "[email protected]",
"age": 30,
"department": "engineering"
}
}
script:pre-request {
// Pre-request script
bru.setVar("timestamp", Date.now());
bru.setVar("requestId", Math.random().toString(36));
}
script:post-response {
// Post-response script
if (res.body.id) {
bru.setEnvVar("lastCreatedUserId", res.body.id);
}
}
tests {
test("User created successfully", function() {
expect(res.status).to.equal(201);
expect(res.body.id).to.exist;
});
}
GraphQL Query
meta {
name: GraphQL User Query
type: graphql
seq: 3
}
post {
url: {{baseUrl}}/graphql
}
headers {
Authorization: Bearer {{graphqlToken}}
Content-Type: application/json
}
body:graphql {
query GetUserProfile($userId: ID!) {
user(id: $userId) {
id
name
email
posts {
id
title
content
createdAt
}
}
}
}
body:graphql:vars {
{
"userId": "{{userId}}"
}
}
tests {
test("GraphQL query successful", function() {
expect(res.body.data.user).to.exist;
expect(res.body.data.user.email).to.include("@");
});
}
Environment Variables Setup (environments/)
// environments/development.bru
vars {
baseUrl: https://api-dev.example.com
accessToken: dev-jwt-token-here
apiVersion: v1
}
// environments/production.bru
vars {
baseUrl: https://api.example.com
accessToken: prod-jwt-token-here
apiVersion: v2
}
// environments/local.bru
vars {
baseUrl: http://localhost:3000
accessToken: local-test-token
apiVersion: v1
}
Authentication Flow and Scripts
meta {
name: OAuth Login
type: http
seq: 1
}
post {
url: {{authUrl}}/oauth/token
}
headers {
Content-Type: application/x-www-form-urlencoded
}
body:form-urlencoded {
grant_type: client_credentials
client_id: {{clientId}}
client_secret: {{clientSecret}}
scope: read write
}
script:post-response {
// Save token to environment variables
if (res.body.access_token) {
bru.setEnvVar("accessToken", res.body.access_token);
bru.setEnvVar("tokenType", res.body.token_type);
bru.setEnvVar("expiresIn", res.body.expires_in);
console.log("Access token updated successfully");
}
}
tests {
test("OAuth token received", function() {
expect(res.status).to.equal(200);
expect(res.body.access_token).to.be.a('string');
expect(res.body.token_type).to.equal('Bearer');
});
}
Git Integration Usage
# Version control for Bruno collections
git init
git add .
git commit -m "Initial API collection setup"
# Feature development with branches
git checkout -b feature/new-endpoints
# Add new API endpoints in Bruno
git add api-collection/
git commit -m "Add new user management endpoints"
# Team sharing
git push origin feature/new-endpoints
# Merge after Pull Request review
# Exclude environment-specific files
echo "environments/local.bru" >> .gitignore
echo "environments/secrets.bru" >> .gitignore