Bruno: The Postman alternative you are looking for

· Thomas Taylor

Postman used to be my favorite API testing tool, but the company’s decision to phase out the final local collection storage feature, Scratchpad, in favor of mandatory cloud services, has changed that.

What is the best Postman alternative?

Finding an alternative means it must satisfy the following requirements:

  1. Local collection storage
  2. Git-friendly collection definitions for my team members
  3. CLI that can invoke collections
  4. Beautiful desktop GUI
  5. No forced account login

with a nice-to-have being open-source.

With that in mind, I came across a service that fulfills all the requirements: bruno.

What is Bruno

Bruno is an open-source Postman alternative that aims to provide a seamless offline experience for testing APIs.

It also plays nicely with Git by using a markdown language, Bru, for defining collections.

Installing Bruno

For MacOS users, installing bruno is easy with brew:

1brew install bruno

It’s also supported in many other popular package managers:

1# On Windows via Chocolatey
2choco install bruno
4# On Windows via Scoop
5scoop bucket add extras
6scoop install bruno
8# On Linux via Snap
9snap install bruno

Migrating from Postman

If you’re planning to migrate from Postman to Bruno, there are import options for collections and environments. For me, it was as simple as exporting the collections/environments in JSON format and importing them.

Scripting in Bruno

Like Postman, Bruno offers scripting capabilities for automating your workflow. I do not use this feature in either solution, but there is more information about it in the Bruno documentation.

Using Bruno CLI

In this section, I will use the Cat Fact API as an example collection.

Installing Bruno CLI

Firstly, let’s install the Bruno CLI using npm:

1npm install -g @usebruno/cli

Define a collection for catfacts

I opened Bruno and created a new collection named Cat Facts API with a single GET request named Get Random Fact.

The cat facts api collection shown in the Bruno desktop application

When creating my collection, Bruno prompted me to select a folder to store my collection in.

That folder had this structure:

2├── Get Random Fact.bru
3├── bruno.json
4└── environments
5    └── production.bru

Get Random Fact.bru had file contents like this:

 1meta {
 2  name: Get Random Fact
 3  type: http
 4  seq: 1
 7get {
 8  url: {{baseUrl}}/fact
 9  body: none
10  auth: none

bruno.json had file contents like this:

2  "version": "1",
3  "name": "Cat Facts API",
4  "type": "collection"

and the production.bru file looked like this:

1vars {
2  baseUrl:

Invoke a collection from the Bruno CLI

I navigated to the collection folder and ran the following command:

1bru run --env production


1Running Folder Recursively 
3Get Random Fact (200 OK) - 177 ms
5Requests:    1 passed, 1 total
6Tests:       0 passed, 0 total
7Assertions:  0 passed, 0 total
8Ran all requests - 177 ms

This executes every .bru file in the folder.

Bruno additionally gives the ability to run single requests:

1bru run Get\ Random\ Fact.bru --env production


1Running Request 
3Get Random Fact (200 OK) - 175 ms
5Requests:    1 passed, 1 total
6Tests:       0 passed, 0 total
7Assertions:  0 passed, 0 total
8Ran all requests - 175 ms


Reply to this post by email ↪