Back to Resources Resource

Bruno - The Git-Friendly API Client

Open-source API client that stores collections as files. Version control your API tests, collaborate with git, no cloud sync needed.

Tired of your API collections living in the cloud, locked behind a subscription, and impossible to version control? Bruno is a revolutionary open-source API client that stores everything as plain text files - right in your git repository.

📂

Git-Native API Collections

Your API tests live alongside your code. Version control, branch, merge, and collaborate - just like your source code. No cloud sync, no vendor lock-in.

Bruno in Action

Bruno stores each request as a .bru file using a simple, readable format that plays perfectly with git:

my-project/ bruno-collection/ bruno.json auth/ login.bru register.bru users/ get-user.bru create-user.bru environments/ dev.bru prod.bru Bruno COLLECTIONS auth users POST /api/auth/login { "email" : "test@example.com" "password" : "***" } Send 200 OK Files in Git Repository Bruno Desktop App

Bruno collections are just files in your git repo - branch, merge, and review API changes like code

Key Features

📁

File-Based Storage

Collections stored as plain text .bru files. Human-readable, diff-friendly, no proprietary formats

🔀

Git-Friendly

Version control your API tests. Branch, merge, PR review - works with any git workflow

🔒

No Cloud Required

Everything runs locally. No accounts, no sync, no subscriptions. Your data stays yours

📜

Scripting Support

Pre/post request scripts in JavaScript. Set variables, validate responses, chain requests

Practical Examples

Here's what a Bruno .bru file looks like - simple, readable, and git-friendly:

login.bru
meta {
  name: Login User
  type: http
  seq: 1
}

post {
  url: {{baseUrl}}/api/auth/login
  body: json
  auth: none
}

headers {
  Content-Type: application/json
}

body:json {
  {
    "email": "{{email}}",
    "password": "{{password}}"
  }
}

script:post-response {
  // Save token for subsequent requests
  if (res.status === 200) {
    bru.setEnvVar("authToken", res.body.token);
  }
}

Environment files keep your secrets separate and environment-specific:

environments/dev.bru
vars {
  baseUrl: http://localhost:3000
  email: dev@example.com
  password: devpassword123
}

vars:secret [
  authToken
]

Pre-request scripts let you set up dynamic values:

create-user.bru
meta {
  name: Create User
  type: http
}

post {
  url: {{baseUrl}}/api/users
  body: json
  auth: bearer
}

auth:bearer {
  token: {{authToken}}
}

body:json {
  {
    "name": "{{$randomFullName}}",
    "email": "{{$timestamp}}@test.com"
  }
}

script:pre-request {
  // Generate unique test data
  const timestamp = Date.now();
  bru.setVar("uniqueId", timestamp);
}

assert {
  res.status: eq 201
  res.body.id: isDefined
}

Why Developers Love It

  • True Version Control - API changes show up in git diffs and code reviews, not hidden in cloud sync
  • No Subscription Needed - 100% free and open source. No paid tiers, no feature limits
  • Team Collaboration via Git - Use your existing git workflow. No inviting teammates to yet another platform
  • Postman Import - Migrate existing collections with one click. No rewriting from scratch
  • Offline First - Works without internet. No cloud dependency means no cloud outages
  • CLI for CI/CD - Run collections in your pipeline with bru run

Bruno vs Postman Comparison

Feature Bruno Postman
Storage Local files in git Cloud-synced
Version Control Native git support Workspace history (limited)
Pricing Free forever Free tier + paid plans
Offline Mode Full functionality Limited without sync
Data Privacy 100% local Cloud-stored
Team Collaboration Git branches/PRs Paid team workspaces
CI/CD Integration CLI included free Newman (separate tool)

Cheatsheet

Quick reference for the .bru file format and common patterns:

Block Purpose Example
meta { } Request metadata name: Get Users
get/post/put { } HTTP method & URL url: {{baseUrl}}/api
headers { } Request headers Authorization: Bearer {{token}}
body:json { } JSON request body { "key": "value" }
auth:bearer { } Bearer token auth token: {{authToken}}
script:pre-request { } Run before request bru.setVar("ts", Date.now())
script:post-response { } Run after response bru.setEnvVar("id", res.body.id)
assert { } Response assertions res.status: eq 200

Pro Tips

🔗

Chain Requests with Variables

Use bru.setVar() in post-response scripts to pass data between requests. Perfect for auth flows where login returns a token needed for subsequent calls.

🏃

Run in CI/CD with bru CLI

Install the CLI with npm i -g @usebruno/cli and run collections in your pipeline: bru run --env dev. Get test results in JUnit format for CI integration.

📥

Migrate from Postman

Export your Postman collection as JSON, then use Bruno's import feature. Your requests, environments, and even scripts will be converted to .bru files automatically.

🔐

Secure Secrets with vars:secret

Mark sensitive variables with vars:secret block. These won't be stored in files - they're entered at runtime or via environment variables in CI.

📂

Organize with Folders

Create subfolders to group related requests (auth/, users/, products/). Each folder can have its own folder-level scripts and headers that apply to all requests inside.

Getting Started

  1. 1

    Download Bruno

    Visit usebruno.com and download for Windows, Mac, or Linux. Also available via brew, snap, and chocolatey.

  2. 2

    Create or Import a Collection

    Start fresh with "New Collection" or import existing Postman/Insomnia collections. Choose a folder inside your project repo.

  3. 3

    Add to Git

    Run git add . to track your collection. Now your API tests are part of your codebase.

  4. 4

    Start Testing

    Create requests, set up environments, and run your API tests. Changes auto-save to .bru files.

Get Bruno - Free Forever

Stop paying for cloud-synced API clients. Version control your API tests like code with Bruno.

Download Bruno

Explore More Resources