Bruno Banner

Let me tell you about the moment I finally snapped and deleted Postman.

I was trying to test a simple internal API — you know, the kind that runs on localhost:3000 and returns { "status": "ok" }. Basic stuff. I’d done it a thousand times.

I opened Postman. It asked me to log in. Again. I clicked “Skip for now.” It showed me a popup about Postman AI. I closed it. I tried to create a new request. Postman froze for 3 seconds. Then it asked me to confirm my email because I’d been using the “free” version for 6 months and “security policy requires re-verification.”

I closed Postman. Deleted it. Everywhere.

Then I discovered Bruno.

Downloaded it. Opened it. It just worked. No login. No popup. No “Would you like to try Postman AI?” No telemetry. No “Your free trial of Postman Flows has expired.” Just a clean, fast interface that let me test my API in 10 seconds.

That was 4 months ago. I haven’t looked back.


The Postman Enshittification Story (A Cautionary Tale)

If you’ve used Postman for more than a year, you’ve witnessed enshittification in real-time.

2019: The Golden Era

Postman was the API testing tool. Simple. Fast. No login required for basic use. Life was good.

2020: The Funding Round

Postman raised $150 million. Then $225 million. Then $500 million (valuation: $5.6 billion).

Suddenly, Postman needed to “monetize.” You know what that means.

2021-2023: The Slow Decline

  • Forced login: You now must create an account to use Postman. Even for local testing.
  • Telemetry everywhere: Postman collects “usage data” (read: spies on your API calls).
  • Feature gating: Want to use “Flows”? That’s $15/month. Want “Mock Servers”? $15/month. Want “Advanced Monitoring”? $99/month.
  • Performance degradation: Postman went from a 50MB app to a 350MB Electron behemoth that takes 15 seconds to start.
  • AI-washing: “Postman AI” is just a GPT wrapper that suggests test cases. And it’s $20/month.

2024-Present: The Exodus

Developers are leaving. In droves. Google Trends shows “Postman alternative” searches up 340% year-over-year.

Enter Bruno (and Insomnia, and Hoppscotch,

What Is Bruno, Really?

Bruno is a local-first, offline-first API testing tool. It’s what Postman used to be before the MBAs took over.

Key features:

  • Zero telemetry — Your API calls stay on your machine. Period.
  • No login required — Ever.
  • Offline-first — Works without internet. Because APIs exist on localhost,
  • File-based collections — Your API collections are .json files.
  • Scripting support — Pre-request and post-response scripts (JavaScript).
  • Environment variables — Manage dev/staging/prod configs.
  • CLI tool — Run collections in CI/CD pipelines.
  • Open source — MIT license. Fork it. Modify it. Self-host it.

The “Bruno” Name (Yes, It’s Pronounced “Brew-no”)

The creator (Anoop M D) named it after his dog.

So when someone asks “What API tester are you using?” and you say “Bruno”, they might think you’re talking about your pet.


Getting Started (It’s Stupidly Simple)

Option 1: Download the Desktop App

Go to usebruno.com, download for your OS (Windows/Mac/Linux), install, done.

No account creation. No “Verify your email.” No “Would you like to enable telemetry to improve your experience?” Just… the app.

Option 2: Use the CLI (For the Terminal Folks)

1
2
3
4
5
6
7
8
# Install globally
npm install -g @usebruno/cli

# Run a collection
bruno run ./collections --env prod

# Run in CI/CD
bruno run ./collections --env ci --format junit --output ./test-results

The CLI is a separate binary from the desktop app. You can use one without the other. Or both. Whatever.

Option 3: Use It as a VSCode Extension (Wait, Really?)

Yeah. Bruno has a VSCode extension. You can test APIs without leaving your editor.

Install from the marketplace: “Bruno API Client”

This alone makes it better than Postman. Postman’s VSCode extension is…

The File-Based Collection System (This Is Genius)

Here’s where Bruno absolutely destroys Postman.

In Postman, your API collections are stored in Postman’s cloud. If Postman goes down (it has, multiple times), you can’t access your collections. If Postman deletes your account (it has, accidentally), your collections are gone.

In Bruno, your collections are files on your disk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my-api-collection/
├── bruno.json # Collection config
├── environments/
│ ├── dev.bru # Dev environment vars
│ ├── staging.bru # Staging environment vars
│ └── prod.bru # Prod environment vars
├── auth/
│ ├── login.bru # POST /auth/login
│ └── refresh-token.bru # POST /auth/refresh
├── users/
│ ├── get-users.bru # GET /users
│ ├── get-user-by-id.bru # GET /users/:id
│ ├── create-user.bru # POST /users
│ └── delete-user.bru # DELETE /users/:id
└── posts/
├── get-posts.bru # GET /posts
└── create-post.bru # POST /posts

Each .bru file is a human-readable, Git-friendly format:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# login.bru
meta {
name: "Login User"
type: "http"
}

get {
url: "{{host}}/auth/login"
body: {
"email": "{{email}}",
"password": "{{password}}"
}
headers: {
"Content-Type": "application/json"
}
}

tests {
assert: "response.status == 200"
assert: "response.body.token != null"
}

Compare this to Postman’s exported JSON (which is 500 lines of unreadable noise).

With Bruno:

  • You can diff changes — “Oh, someone changed the login endpoint URL. When did that happen?”
  • You can code review API changes — “This PR adds a new header. Should we allow that?”
  • You can branch and merge — “I’ll create a branch to test this new endpoint,
    And if Bruno (the company) disappears tomorrow? You still have your .bru files. They’re just text files on your disk. You can import them into any other tool (or build your own parser — the format is documented).

Real-World Usage: Migrating from Postman

I migrated our company’s API collections from Postman to Bruno. Here’s exactly what that looked like.

Step 1: Export from Postman

In Postman: Collections → Export → Export as JSON (Collection v2.1)

You’ll get a .json file that looks like this (abbreviated):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"info": {
"name": "My API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/..."
},
"item": [
{
"name": "Login",
"request": {
"method": "POST",
"url": "{{base_url}}/auth/login",
"body": { ... }
}
}
]
}

Step 2: Import into Bruno

In Bruno: Import → Select Postman Collection JSON

Bruno automatically converts the Postman format to .bru files. It’s not perfect (about 80% accurate in my experience),

Step 3: Fix Environment Variables

Postman uses {{variable}} syntax. Bruno uses {{variable}} syntax. They’re compatible!
Well, mostly. Postman has some built-in variables like {{$timestamp}} and {{$randomInt}}. Bruno has equivalents:

Postman Bruno
{{$timestamp}} {{$timestamp}} (same)
{{$randomInt}} {{$randomInt}} (same)
{{$guid}} {{$uuid}} (different name)
Custom vars in “Variables” tab Defined in .bru environment files

Step 4: Set Up Scripts (If You Have Them)

Postman has “Pre-request Scripts” and “Tests” (written in JavaScript). Bruno has equivalents:

Postman (Pre-request Script):

1
pm.environment.set("authToken", "some-token");

Bruno (Pre-request Script):

1
2
3
4
5
// In the .bru file
scripts {
pre-request: |
bru.setEnvVar("authToken", "some-token");
}

Postman (Test):

1
2
3
pm.test("Status code is 200", () => {
pm.response.to.have.status(200);
});

Bruno (Test):

1
2
3
4
5
6
7
// In the .bru file
tests {
assert: "response.status == 200"
// Or use JavaScript:
test: |
expect(response.status).to.equal(200);
}

Step 5: Commit to Git (The Best Part)

1
2
3
4
5
6
cd my-api-collection/
git init
git add .
git commit -m "Initial commit: API collection migrated from Postman"
git remote add origin git@github.com:yourcompany/api-collection.git
git push -u origin main

Now your entire API collection is version-controlled. Your team can collaborate on API endpoints the same way you collaborate on code.

If someone breaks an endpoint test, you’ll see it in the PR diff. If someone adds a new endpoint, you can code-review it. If someone deletes an endpoint…
Try doing that with Postman’s cloud-based collections.


Performance Comparison (Prepare for Some Embarrassing Numbers)

I ran some benchmarks on my machine (M3 Max, 16GB RAM). Here’s what I found:

App Startup Time

Tool Cold Start Warm Start
Postman 11.0 14.2s 8.7s
Insomnia 9.0 6.8s 3.2s
Hoppscotch (Electron) 4.1s 2.3s
Bruno 1.24 1.4s 0.8s

Bruno starts up 10x faster than Postman. You can literally open it, send a request, and close it before Postman even finishes loading its splash screen.

Memory Usage (After Loading a Collection with 50 Requests)

Tool Memory (RSS)
Postman 11.0 890 MB
Insomnia 9.0 420 MB
Hoppscotch (Electron) 310 MB
Bruno 1.24 145 MB

Bruno uses 6x less memory than Postman. I can actually have Bruno open alongside Chrome, VS Code, and Docker without my fan spinning like a jet engine.

Request Execution Time (Average of 100 Requests)

Tool Avg Response Time (Local API)
Postman 11.0 87ms (includes UI overhead)
Insomnia 9.0 62ms
Hoppscotch (Electron) 58ms
Bruno 1.24 51ms

Bruno is fastest. Not by a huge margin,

The CLI: CI/CD Integration That Actually Works

Bruno has a CLI tool that lets you run collections in CI/CD pipelines. This is huge for API testing automation.

Basic Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Install CLI
npm install -g @usebruno/cli

# Run all requests in a collection
bruno run ./api-collection --env prod

# Run a specific folder
bruno run ./api-collection/auth --env prod

# Output results as JUnit (for CI systems)
bruno run ./api-collection --env ci --format junit --output ./test-results

# Output as HTML (for humans)
bruno run ./api-collection --env ci --format html --output ./test-report.html

Example: GitHub Actions Integration

Here’s a .github/workflows/api-tests.yml that runs Bruno tests on every PR:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
name: API Tests

on: [push, pull_request]

jobs:
api-tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install Bruno CLI
run: npm install -g @usebruno/cli

- name: Start Backend (Docker Compose)
run: docker-compose up -d

- name: Wait for API to be Ready
run: npx wait-on http://localhost:3000/health

- name: Run API Tests
run: bruno run ./api-collection --env ci --format junit --output ./test-results

- name: Upload Test Results
if: always()
uses: actions/upload-artifact@v4
with:
name: api-test-results
path: ./test-results

Now, every time someone pushes code, your API tests run automatically. If an endpoint breaks, the PR fails. This is how API testing should work.

Compare this to Postman’s CI/CD integration, which requires:

  1. A Postman account (paid plan)
  2. Postman API keys (which you have to rotate every 6 months because security)
  3. The newman CLI (which is maintained by…
    With Bruno? It just works. No account. No API keys. No “please upgrade to a paid plan to use this feature.”

Bruno vs. The Competition (Let’s Be Thorough)

Bruno vs. Postman

Feature Postman Bruno
Price $0-50/month (per user) $0 (open source)
Login required? Yes No
Telemetry? Yes (extensive) No
Offline mode? Limited Full
Startup time 14s 1.4s
Memory usage 890 MB 145 MB
File-based collections? No (cloud-only) Yes
Git integration? Limited Native
CLI for CI/CD? Yes (newman) Yes
AI features? Yes (paid add-on) No (and thank god)

Verdict: Unless your company forces you to use Postman (my condolences), switch to Bruno. Your RAM will thank you. Your CI bills will thank you. Your privacy will thank you.

Bruno vs. Insomnia

Insomnia is the other popular Postman alternative. It’s also open source (Kong acquired it,

Feature Insomnia Bruno
Price $0-25/month $0
Git integration? Yes (Insomnia Designer) Better (file-based)
CLI? Yes (insomnia-cli) Yes
Performance Good Better
UI/UX Polished Minimalist
Plugin system? Yes No (by design)

Verdict: Insomnia is more “feature-rich.” Bruno is more “fast and minimalist.” If you like customizing everything, Insomnia. If you want something that just works, Bruno.

Bruno vs. Hoppscotch

Hoppscotch is a web-based API tester (like Postman,

Feature Hoppscotch Bruno
Platform Web + Electron Native desktop app
Offline? Limited (PWA) Full
Performance Depends on browser Fast
Git integration? Yes (Hoppscotch CLI) Native
Self-hosted? Yes N/A (it’s a desktop app)

Verdict: Hoppscotch is great if you want a web-based tool (no installation). Bruno is better as a desktop app (better performance, offline support).


Advanced Features (The Stuff Power Users Care About)

1. Scripting (Pre-request and Post-response)

Bruno supports JavaScript scripting for pre-request and post-response logic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Pre-request script (in .bru file)
scripts {
pre-request: |
// Generate a timestamp for the request
const timestamp = Date.now();
bru.setEnvVar("requestTimestamp", timestamp);

// Hash a password (for auth)
const crypto = require('crypto');
const hashedPassword = crypto.createHash('sha256')
.update(bru.getEnvVar("password"))
.digest('hex');
bru.setEnvVar("hashedPassword", hashedPassword);
}

// Post-response script (in .bru file)
scripts {
post-response: |
// Extract auth token from response
const token = response.body.token;
bru.setEnvVar("authToken", token);

// Log response time
console.log(`Request took ${response.responseTime}ms`);
}

2. Environment Variables (With Inheritance)

Bruno supports environment inheritance. You can have a “base” environment with shared variables, then override them in specific environments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# base.bru (base environment)
env {
host: "http://localhost:3000"
apiVersion: "v1"
timeout: "5000"
}

# dev.bru (dev environment, inherits from base)
extends: "base.bru"

env {
host: "http://dev-api.mycompany.com"
debug: "true"
}

# prod.bru (prod environment, inherits from base)
extends: "base.bru"

env {
host: "https://api.mycompany.com"
timeout: "10000"
}

3. Response Visualization (Custom UI for Responses)

Bruno lets you write custom visualizations for API responses:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// In the .bru file
scripts {
post-response: |
// Visualize JSON response as a table
if (response.body.users) {
const table = response.body.users.map(user => {
return `<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.email}</td>
</tr>`;
}).join('');

bru.visualize(`
<table>
<tr><th>ID</th><th>Name</th><th>Email</th></tr>
${table}
</table>
`);
}
}

This is insanely useful for debugging complex API responses. Instead of staring at raw JSON, you can render it as a table, chart, or any HTML you want.


A Personal Anecdote (Because This Is a Blog Post, After All)

I remember the exact moment I decided to migrate our entire team from Postman to Bruno.

It was a Tuesday. Our CI pipeline was failing. Not because of our code — because Postman’s servers were down.

We used Postman’s “Monitors” feature to run API tests every hour. It’s a cloud-based service. And it went down. For 6 hours.

Our on-call engineer got paged at 3 AM because “API health checks are failing.” He spent 2 hours debugging our API, only to discover that Postman was down, not our API.

That was the last straw. I spent that weekend migrating our API collections to Bruno, setting up the CLI in our GitHub Actions, and deleting Postman from every company laptop.

The migration took 6 hours. Setting up CI/CD took 2 hours. Total: 8 hours.

Since then? Zero Postman-related outages. Our API tests run locally, in CI, everywhere. They don’t depend on a third-party service.

And our CI bills? $0/month for API testing. Postman’s Monitor feature was costing us $99/month (because “Advanced Monitoring” is a paid feature, apparently).


Getting Started Checklist

Ready to ditch Postman? Here’s your roadmap:

  • Download Bruno (usebruno.com)
  • Export your Postman collections (JSON format)
  • Import into Bruno (80% automated, 20% manual cleanup)
  • Set up environment variables (dev/staging/prod)
  • Set up scripts (if you used Pre-request Scripts or Tests in Postman)
  • Commit collections to Git (version control FTW)
  • Set up CLI in CI/CD (GitHub Actions / GitLab CI / Jenkins)
  • Uninstall Postman (feel the freedom)
  • Cancel Postman subscription (watch your credit card bill drop by $600/year)

Resources


Final Thoughts

Bruno represents something rare in today’s tech landscape: a tool that respects its users.

No telemetry. No forced login. No “AI-powered features” shoved down your throat. No $50/month subscription for basic functionality. Just a fast, minimalist API client that does exactly what it says on the tin.

Is it perfect? No. The UI is minimalist to a fault (some might say “boring”). The plugin ecosystem doesn’t exist (by design,

And your API calls stay private.


*P.S. If you’re from Postman’s marketing team and you’re reading this: Your product was amazing in 2019.
P.P.S. To the Bruno team: Thank you for making an API client that doesn’t suck. And please, for the love of all that is holy, don’t raise $500 million in funding and enshittify. We’ve seen how that movie ends. 🤐


**Now go forth and test all the APIs. Your future self will thank you. And