DEV Community

JessYT
JessYT

Posted on • Originally published at jessinvestment.com

Bruno: Manage Your API Collections as Plain Files in Git

Bruno: Manage Your API Collections as Plain Files in Git

Bruno is an open-source API client that stores your collection of API requests as plain text files inside your project instead of in the cloud. It targets anyone who used Postman but found the cloud sync and account login a burden. This post walks through exactly what Bruno replaces, what difference it actually makes to keep collections as files, and the order to follow from first install and first request through environment variables, tests, and the CLI.

Bruno strips away Postman's cloud dependency

An API client is a tool for building and sending HTTP requests, then grouping those requests into collections to manage them. Postman is the de facto standard in this space, but over time it has accumulated cloud-first features like workspace sync, account login, and per-seat team billing. The disappearance of the scratchpad style—firing off requests quickly without logging in—is also cited as one of the reasons developers started looking for alternatives.

Bruno takes the opposite direction. It doesn't sync your request collections to the cloud—it stores them as folders and text files inside the repository you're working in. There's no need to create an account, and the data deliberately stays on your local machine until you hand it off through Git or file sharing. The core features are open source, and some add-on features come in a paid Golden Edition.

Item Cloud-centric client Bruno
Where collections are stored Mostly the service's cloud Local files (.bru), inside the project folder
Account / login Usually required Not required
Version control In-service history Git directly (diff · PR review)
Collaboration Workspace invites · seats Shared via repo push/pull
License Varies by product Open source + paid Golden Edition

Collections as files means you treat them like code

Bruno's biggest difference is that it keeps collections as files on disk rather than data that exists only inside the app's screen. A single request lands as a single .bru file, and the folder structure is the collection structure. That makes the following possible.

  • You keep your API collection in the same repository as your code and commit them together. When an endpoint changes, the request change rides in the same PR as the code change.
  • You can see how a request changed line by line with git diff, and a teammate reviews it.
  • Sharing with the team is just pulling down the repository—no separate invite process. Access permissions follow the Git permission system you already use.

The .bru format used here is not JSON or YAML but a separate markup format called Bru. It's designed to write the request · headers · body · assertions as human-readable blocks. For reference, Bruno is moving toward recommending the OpenCollection YAML format for new collections, but the official docs state that existing .bru files continue to be supported.

The order for installing and sending your first request

Getting started is simple.

  1. Download the desktop app from the official site (usebruno.com). On macOS you can also install via Homebrew (brew install bruno), and on Windows via package managers like winget.
  2. Open the app and create a new collection with Create Collection—you pick the folder location on disk yourself. This folder is exactly what you'll manage with Git.
  3. Inside the collection, add a request with New Request, enter the method and URL, and send it. At this point a per-request .bru file is created in the folder.
  4. If you're already using Postman, you can move over with the import feature that brings Postman collections and environments into Bruno.

When you create a request, the file that lands on disk looks roughly like this. The values you filled in on screen show up as-is in plain text.

meta {
  name: List users
  type: http
  seq: 1
}

get {
  url: {{baseUrl}}/api/users
  body: none
  auth: none
}

headers {
  Accept: application/json
}

assert {
  res.status: eq 200
}
Enter fullscreen mode Exit fullscreen mode

How environments, variables, scripts, and tests are split up

Environments and variables

For cases where the call target changes—dev, staging, production—you can split things into Environments. If you slot in a variable like {{baseUrl}} from the example above, you reuse the same request just by switching the environment. Variables can be defined at request · environment · collection scope.

Pre- and post-scripts

You can attach scripts that run before a request is sent (pre-request) and after the response comes back (post-response). They're used to automate flows like generating a token and putting it in a header before sending, or pulling a value out of the response and saving it as a variable for the next request.

Assertions and tests

You can set up assertions to check whether a response's status code or body values match expectations. The assert block in the example above is one such case, verifying that the response status is 200. Beyond checking a one-off request, they're good to collect for regression testing.

You can drop it into a CI pipeline with the CLI

Bruno has a CLI that provides the bru run command. Since it runs collections from the command line without opening the desktop app, you can drop the requests and assertions you've written straight into a CI/CD pipeline and run them automatically. Because the collection lives as files inside the repository, a runner that checks out the code can run the same bundle of requests with no separate sync—a natural fit.

# Run the whole collection against a specific environment, from the collection folder
bru run --env staging
Enter fullscreen mode Exit fullscreen mode

Things worth knowing up front

  • It's mid-format-transition. New collections are moving toward recommending OpenCollection YAML, while .bru continues to be supported. If you're starting fresh, it's worth checking once which format to create in.
  • The team-sharing model is different. Instead of workspace invites, it assumes Git repository access. For a team that doesn't use Git, the collaboration upside weakens.
  • Be careful with secrets. Because collections are plain text files, if you write API keys and other secrets directly and commit them, they're exposed in the repository. Keep secrets separated into variables and environments and exclude them from commits.
  • Check the paid boundary. The core features are free, but some features come in the Golden Edition. It's good to look ahead at which side the feature you need is on.

When it's a good fit

It suits cases where you want to version-control code and API requests together in the same repository, where you want to avoid cloud sync or account login and work locally and fast, and where you want to build a flow that reviews request changes as PRs. Conversely, if you're already comfortable with GUI workspace-based sharing, or your team doesn't use Git, the upside shrinks. If you're on Postman right now, the low-friction approach is to import a collection, move just one directory over, give it a trial run, and then decide.

Install · setup notes — Get the desktop app from usebruno.com, or install via Homebrew · winget. When you create a collection, pick the storage folder yourself and manage that folder with Git. Separate secrets into variables · environments and exclude them from commits. The CLI runs collections from the command line with bru run.

Sources

This is an objective overview based on the official docs · site, not a hands-on review. Features · license scope can change by version, so check the latest details in the official docs before adopting.


Original with full infographics and visual structure: https://jessinvestment.com/bruno-manage-your-api-collections-as-plain-files-in-git/

Top comments (0)