Bruno v4 Migration Guide: Breaking Changes #8257
helloanoop
started this conversation in
General
Replies: 2 comments 2 replies
-
|
Woah, you guys are planning v4 already. Really excited |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
About Env Vars change; I need clarification on this please? |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Bruno v4 changes how secrets are stored and how environment variables behave. It also adds new optional fields to requests and environments (like descriptions and variable types), so their schema changes slightly. Some of these changes require action before upgrading. Others are good to know if your team works across mixed Bruno versions.
Contents
1. Secret Manager configuration is moving into your environments
What's changing
In v4, external secrets configuration no longer lives in a
secrets.jsonfile at the root of your collection. It moves into your environment files, under a newexternalSecretssection, and is managed from the Environment UI instead of from Collection Settings > Secrets.You also get a simpler way to reference a secret, by its name directly:
{{name.keyname}}{{$secrets.name.keyname}}Both resolve to the same value for now, so nothing breaks immediately. The old
{{$secrets.*}}form is deprecated: it will keep working for 3 months to give you time to migrate, then support is removed. There's no rush, update references to{{name.keyname}}whenever it's convenient within that window. Wherever the old syntax appears in your scripts and requests, the app marks it with an underline and a hover tooltip pointing you to the new form.Why we're doing this
Secrets are environment-specific. Your Production token is not your Staging token, so keeping the configuration alongside the environment it belongs to is clearer and removes a separate root-level file to manage. It also makes the environment the single source of truth for secrets, brings full secret-manager support to the CLI across AWS, Azure, and Vault, and adds support for workspace and global environments, which the old
secrets.jsonmodel could not express.How it behaves today (< v4)
secrets.jsonfile at the collection root.{{$secrets.name.keyname}}.What you need to do
If you use the Bruno app (GUI): nothing.
Migration is automatic. When you open a collection in v4, Bruno moves your secret configuration from
secrets.jsoninto the relevant environment files in the background, and deletessecrets.jsononce migration succeeds. Your secret values are never written to disk, only the mappings and provider configuration are moved. When you next open Collection Settings > Secrets, you'll see a short notice that Secret Manager now lives in environments, with a button to take you there.If you run from the CLI or CI:
The CLI does not migrate on its own. If your collection still uses external secrets from a
secrets.json, your run will show a warning to open the collection in the Bruno app and go to Collection Settings > Secrets to complete the migration. Once you've done that in the app, the configuration lives in your environment files and your CLI and CI runs pick it up from there, provided you pass the required environment to the run (for examplebru run --env <name>). The warning does not block the run.Before and after
Before (
secrets.jsonat collection root){ "type": "aws-secrets-manager", "data": [ { "environment": "Production", "secrets": [ { "name": "dbPassword", "secretName": "prod/db/credentials", "enabled": true }, { "name": "apiKey", "secretName": "prod/payment-gateway/api-key", "enabled": true } ] } ] }After (
environments/production.yml)2. Environment variable changes are saved to disk by default
What's changing
In v4, scripts that modify environment variables automatically persist those changes to disk. This makes script-driven variable updates consistent and predictable.
The thing to watch out for: if your scripts set tokens, credentials, or other sensitive values with
bru.setEnvVar(),bru.deleteEnvVar(), orbru.setGlobalEnvVar(), those values will now be written to your environment file and could be committed to version control by accident.Why we're doing this
In earlier versions this behavior was inconsistent: in some scenarios variable changes written by scripts were saved to the file system, and in others they were not, which made it hard to predict what would end up on disk. v4 makes the behavior consistent so that what a script sets is what gets persisted.
How it behaves today (< v4)
In v3.5 and earlier, whether a scripted variable change is written to disk is inconsistent and depends on which API you use:
bru.setEnvVar()does not write to disk by default. The value lives in memory for the run only. Persisting requires explicitly passing{ persist: true }, and in that case only string values are allowed.bru.setGlobalEnvVar()already writes to the global environment file, with no opt-in. However, only string values survive to disk: numbers, booleans, and objects are kept in memory for the run but are dropped when the file is written.bru.setVar()andbru.deleteVar()are in-memory only and never written to disk.The string-only limit is not specific to globals. The current file format stores only string values for environment variables, so any non-string value set from a script is dropped on save.
So a value you set with
setEnvVar()usually disappears after the run, while the same pattern withsetGlobalEnvVar()is saved (as long as it is a string). v4 removes both rough edges: it adds real data-type support to the file format (see section 4), and it persists environment variable changes by default, so the{ persist: true }opt-in is no longer needed.Who is affected
You are affected if any of the following apply:
bru.setEnvVar()orbru.deleteEnvVar(). These did not write to disk by default before v4, and now they do.setEnvVar()values stayed in memory and were not written to disk.Note:
bru.setGlobalEnvVar()already persists string values today, so those are written to disk in v3.5 too. It is worth auditing for the same reason, even though its persistence is not changing in v4.You are not affected if:
baseUrl, a counter, or a request ID).How to prepare
bru.setEnvVar(),bru.deleteEnvVar(), andbru.setGlobalEnvVar()usage that handles sensitive values.bru.setVar()andbru.deleteVar(), which keep the value in memory for the run instead of persisting it. Non-sensitive values do not need to change.3. Multiple WebSocket messages
What's changing
In v4, you can add multiple WebSocket messages to a single request. To support this, Bruno saves WebSocket requests in a new message format.
Why we're doing this
Previously a WebSocket request could hold only a single message. Real WebSocket workflows often send a sequence of messages on one connection, so v4 lets you define more than one message per request and choose which to send.
How it behaves today (< v4)
A WebSocket request stores a single message. The older single-message schema cannot represent more than one message per request.
Who is affected
You are not affected if you don't use WebSocket requests, or if your collections use the BRU format.
What you need to do
Nothing to migrate. You can upgrade to v4 without any prep. The main thing to plan for is mixed-version teams: if some teammates are still on older versions, the simplest fix is to have everyone upgrade to v4.
Before and after (YAML schema)
Before (single message)
After (multiple messages)
4. Descriptions and variable types
What's changing
In v4, you can add descriptions to params, headers, multipart form fields, variables, and more, and assign types to your variables. Bruno stores these as annotations on the line above each pair: descriptions as
@description('...'), and types as@string,@number,@boolean, or@object.Why we're doing this
These annotations let you document what each field is for and give variables real types instead of treating every value as a string, which makes collections easier to read and variable handling more accurate.
How it behaves today (< v4)
Params, headers, and variables are stored as plain pairs with no description and no type. Every variable value is effectively a string.
Who is affected
The change matters only when opening v4 collections in older Bruno versions:
You are not affected if everyone on your team is on v4, or if you don't add descriptions or variable types.
What you need to do
Nothing to migrate before upgrading. The mixed-version caveat is the same as for WebSocket messages: if teammates are on older versions, have everyone upgrade to v4.
Before and after (BRU schema)
Before (pre-v4)
After (v4)
5. CLI JUnit report: classname now uses the request path
This is a potential breaking change for CI reporting: it changes the contents of the JUnit XML the CLI produces, which downstream tools parse.
What's changing
In the CLI JUnit reporter, each test case's
classnameattribute changes from the request URL to the collection path to the request, including the request name (for exampleUsers/Get Usersfor a requestGet Usersinside aUsersfolder).Why we're doing this
CI tools like Xray and Azure DevOps use
classname+nameas a test's unique identifier. Because the URL changes per environment/region, the same test produced a differentclassnamein each environment and showed up as duplicate test cases. The collection path is stable across environments, so the same test now maps to a single entry, and the path keeps it unique because the same request name can exist in multiple folders.How it behaves today (< v4)
classnameis set to the request URL, so running the same collection against staging and production yields differentclassnamevalues for the same test:Who is affected
classnameexpecting a URL.You are not affected if you don't consume the CLI's JUnit output, or you don't key on
classname.What you need to do
Update any CI mapping or scripts that key on
classnameto expect the collection path (Folder/Request Name) instead of a URL. If you only need the request name, extract it from the path. After the change, the same test run across environments produces identicalclassnamevalues, which is the intended behavior.Before and after
Before (URL, varies per environment)
After (collection path, stable across environments)
Before you upgrade checklist
bru.setEnvVar(),bru.deleteEnvVar(), andbru.setGlobalEnvVar()usage for sensitive values, and move those tobru.setVar()/bru.deleteVar().The new description/variable-type fields behave differently depending on the teammate's version:
Applies to both BRU and YAML formats.
External secrets: if your collection fetches secrets from a secret manager and you've migrated it to v4, the secret config now lives in the environment files (not
secrets.json). A teammate on a pre-v4 version won't be able to access those secrets, since older versions don't read the new location.WebSocket requests with multiple messages (saved in the new format) may not load correctly in v3.5.0 or earlier. Affects only YAML collections.
classnamefrom the CLI JUnit report and expects the request URL, update it to expect the collection path (Folder/Request Name) instead.Once on v4
secrets.json, then go to Collection Settings > Secrets > Go to Environment to verify the secrets have migrated successfully.{{$secrets.*}}references to{{name.keyname}}when convenient.Beta Was this translation helpful? Give feedback.
All reactions