Skip to main content

Overview

Bruno stores collections as plain text files directly on your filesystem, making it perfect for version control. Unlike cloud-based API tools, Bruno uses Git-friendly formats that enable true collaboration through pull requests, branches, and code reviews.

File Structure

Bruno collections are organized in a simple directory structure:
my-api-collection/
├── bruno.json              # Collection configuration
├── environments/           # Environment variables
│   ├── Development.bru
│   ├── Staging.bru
│   └── Production.bru
├── auth/                   # Requests organized by folder
│   ├── login.bru
│   └── refresh-token.bru
├── users/
│   ├── create-user.bru
│   ├── get-user.bru
│   └── folder.bru         # Folder-level configuration
└── collection.bru         # Collection-level scripts

Collection Configuration

The bruno.json file contains collection settings:
bruno.json
{
  "version": "1",
  "name": "bruno-testbench",
  "type": "collection",
  "scripts": {
    "moduleWhitelist": ["crypto", "buffer", "form-data"],
    "additionalContextRoots": ["../additional-context-root-lib"]
  },
  "clientCertificates": {
    "enabled": true,
    "certs": []
  },
  "presets": {
    "requestType": "http",
    "requestUrl": "http://localhost:6000"
  }
}

Request Files

Each request is stored as a .bru file using plain text markup:
ping.bru
meta {
  name: ping
  type: http
  seq: 1
}

get {
  url: {{host}}/ping
  body: none
  auth: none
}

script:pre-request {
  bru.runner.stopExecution();
}

Environment Files

Environment variables are stored in .bru files:
environments/Prod.bru
vars {
  host: https://testbench-sanity.usebruno.com
  localhost: http://localhost:8081
  bearer_auth_token: your_secret_token
  basic_auth_password: della
  env.var1: envVar1
  foo: bar
  echo-host: https://echo.usebruno.com
}

Git Workflow

1

Initialize Git repository

Create a new Git repository for your collection:
cd my-api-collection
git init
git add .
git commit -m "Initial API collection"
2

Create a .gitignore file

Add files you want to exclude:
.gitignore
# Environment-specific secrets
environments/Local.bru

# OS files
.DS_Store
Thumbs.db

# IDE files
.vscode/
.idea/
3

Push to remote repository

Add a remote and push:
git remote add origin https://github.com/username/api-collection.git
git branch -M main
git push -u origin main

Collaboration Workflows

Feature Branch Workflow

1

Create a feature branch

git checkout -b feature/add-payment-endpoints
2

Add new requests

Create new .bru files in Bruno and organize them:
payments/
├── create-payment.bru
├── get-payment.bru
└── refund-payment.bru
3

Commit your changes

git add payments/
git commit -m "Add payment API endpoints"
4

Push and create pull request

git push -u origin feature/add-payment-endpoints
Then create a PR on GitHub/GitLab for review.

Team Collaboration

Clone Collection

Team members can clone and start working:
git clone https://github.com/team/api-collection.git
cd api-collection
Open the folder in Bruno to start testing.

Pull Latest Changes

Stay in sync with team updates:
git pull origin main
Bruno will automatically reflect the changes.

Review Changes

Review API changes in pull requests:
  • See exactly what requests changed
  • Review test scripts and assertions
  • Check environment variable updates

Resolve Conflicts

Merge conflicts are easy to resolve since .bru files are plain text:
git mergetool

Branch Strategies

Gitflow for API Collections

  • Production-ready API tests
  • Only merge from release branches
  • Protected branch with required reviews
git checkout main
git merge release/v1.0
git tag v1.0.0

Managing Secrets

Never commit sensitive data to version control!

Using Environment-Specific Files

Create separate environment files and exclude secrets:
.gitignore
# Exclude local development secrets
environments/Local.bru
environments/.env.local

# Exclude any files with secrets
**/secrets.bru
**/*.secret.bru

Environment Variable Templates

Commit template files instead:
environments/Production.bru.template
vars {
  host: https://api.production.com
  api_key: ${API_KEY}  # Set in CI/CD
  auth_token: ${AUTH_TOKEN}  # Set in CI/CD
}
Team members copy and fill in their own values:
cp environments/Production.bru.template environments/Local.bru
# Edit Local.bru with actual secrets

Using Process Environment Variables

Reference system environment variables in Bruno:
environments/Prod.bru
vars {
  host: https://api.production.com
  api_key: {{process.env.API_KEY}}
  db_password: {{process.env.DB_PASSWORD}}
}
Set them in your shell or CI/CD:
export API_KEY="secret123"
export DB_PASSWORD="dbpass456"
bru run --env Prod

Git Best Practices

Follow conventional commit format:
git commit -m "feat: add user authentication endpoints"
git commit -m "fix: correct OAuth2 token refresh logic"
git commit -m "test: add assertions for error responses"
git commit -m "docs: update API endpoint documentation"
Each commit should represent a single logical change:
# Good: One feature per commit
git add users/create-user.bru
git commit -m "Add create user endpoint"

git add users/delete-user.bru
git commit -m "Add delete user endpoint"

# Avoid: Multiple unrelated changes
git add users/*.bru payments/*.bru
git commit -m "Add stuff"
Protect important branches on GitHub/GitLab:
  • Require pull request reviews
  • Require status checks (CI tests) to pass
  • Require branches to be up to date
  • Restrict who can push
Tag important versions:
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
Delete merged feature branches:
git branch -d feature/user-api
git push origin --delete feature/user-api

Monorepo vs Multi-repo

Keep all API collections in one repository:
api-collections/
├── user-service/
│   ├── bruno.json
│   └── requests/
├── payment-service/
│   ├── bruno.json
│   └── requests/
└── auth-service/
    ├── bruno.json
    └── requests/
Pros:
  • Single source of truth
  • Easy to share environments
  • Simpler dependency management
Cons:
  • Larger repository size
  • Requires discipline for organization

Code Review Checklist

When reviewing Bruno collection pull requests:
  • Request URLs use environment variables (not hardcoded)
  • No secrets or sensitive data committed
  • Tests include proper assertions
  • Request names are descriptive
  • Folder organization is logical
  • Environment files follow naming conventions
  • Pre-request and post-response scripts are documented
  • Changes work with existing collection structure

Advanced: Git Hooks

Automate checks with Git hooks:
.git/hooks/pre-commit
#!/bin/bash
# Pre-commit hook to check for secrets

if git diff --cached --name-only | grep -E '\.bru$'; then
  if git diff --cached | grep -iE 'password|secret|api[_-]?key' | grep -v '{{'; then
    echo "Error: Potential secret found in .bru file!"
    echo "Make sure to use environment variables for secrets."
    exit 1
  fi
fi

exit 0
Make it executable:
chmod +x .git/hooks/pre-commit

Integration with Code

Store Bruno collections alongside your application code:
my-app/
├── src/
├── tests/
├── bruno-collections/     # API tests
│   ├── bruno.json
│   └── api/
├── package.json
└── README.md
Add npm scripts:
package.json
{
  "scripts": {
    "test:api": "cd bruno-collections && bru run --env Development",
    "test:api:prod": "cd bruno-collections && bru run --env Production"
  }
}

Why Bruno Works Better with Git

Plain Text Format

.bru files are human-readable text files, perfect for diff tools and merge operations.

File-per-Request

Each request is its own file, preventing merge conflicts when multiple people work on different endpoints.

No Binary Exports

Unlike Postman exports, everything is editable text that works seamlessly with Git.

Offline-First

No cloud sync means full control over your version history through Git.
Pro tip: Use Bruno’s Golden Edition for end-to-end encrypted cloud storage while still maintaining full Git workflow compatibility.

Build docs developers (and LLMs) love