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:
{
"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:
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:
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
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"
Create a .gitignore file
Add files you want to exclude: # Environment-specific secrets
environments/Local.bru
# OS files
.DS_Store
Thumbs.db
# IDE files
.vscode/
.idea/
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
Create a feature branch
git checkout -b feature/add-payment-endpoints
Add new requests
Create new .bru files in Bruno and organize them: payments/
├── create-payment.bru
├── get-payment.bru
└── refund-payment.bru
Commit your changes
git add payments/
git commit -m "Add payment API endpoints"
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: 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:
Branch Strategies
Gitflow for API Collections
Main Branch
Develop Branch
Feature Branches
Release Branches
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
Integration branch for features
Continuous testing against staging
git checkout develop
git merge feature/user-api
Individual API endpoint development
One branch per feature/endpoint group
git checkout -b feature/payment-integration
# Add payment requests
git commit -m "Add payment endpoints with tests"
Prepare for production release
Update environment variables
git checkout -b release/v1.1
# Update production endpoints
git commit -m "Prepare v1.1 release"
Managing Secrets
Never commit sensitive data to version control!
Using Environment-Specific Files
Create separate environment files and exclude secrets:
# 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:
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
Write descriptive commit messages
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"
Use branch protection rules
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
Monorepo Approach
Multi-repo Approach
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
Separate repository per service: user-service-api/
├── bruno.json
└── requests/
payment-service-api/
├── bruno.json
└── requests/
Pros:
Clear service boundaries
Independent versioning
Smaller, focused repositories
Cons:
Harder to share common setups
Need to sync changes across repos
Code Review Checklist
When reviewing Bruno collection pull requests:
Advanced: Git Hooks
Automate checks with Git hooks:
#!/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:
{
"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.