Skip to main content
Bruno v4 changes where secret manager configuration lives. This guide explains what changed, how migration works, and what to watch for.

What changed


How migration works

In the app (automatic)

  1. Open any collection that still has a secrets.json file.
  2. Bruno detects the old format and migrates the configuration to the environment file in the background.
  3. The externalSecrets block appears in the relevant environment file. The original secrets.json is no longer used.
  4. Collection Settings → Secrets tab shows a notice that Secret Manager has moved to the Environment UI, with a button to open it directly.
No manual steps are needed. The migration runs once and is non-destructive.
Migration failure edge case: If secrets.json is marked read-only on disk, the migration will fail. Bruno currently has no fallback for this scenario. You will see a “start a fresh” state and will need to manually re-enter your secret configuration in the Environment UI. This situation is rare but worth checking if migration does not complete as expected: verify that secrets.json is writable before opening the collection.

In the CLI (manual trigger via app)

The CLI does not auto-migrate. If it finds a secrets.json but no externalSecrets block in the environment file, it prints a warning:
Fix: Open the collection in the Bruno app, let the automatic migration run, commit the updated environment file, then re-run the CLI.

Before and after

secrets.json (pre-v4)

Configuration lives at the collection root. All environments share the same vault connection; per-environment secret paths are listed in data[].secrets.

Environment file (v4+)

Configuration is embedded directly in the environment file. Each environment can point to a different vault, region, or key vault independently.

Variable reference in requests

Both work in v4. The old syntax is shown with a deprecation underline in the editor.

Step-by-step migration (app)

1

Open the collection in Bruno

Launch Bruno and open any collection that uses secrets.json.
2

Let the automatic migration run

Bruno detects secrets.json on open and silently migrates the configuration into the correct environment files. A notice appears in Collection Settings → Secrets confirming the move.
3

Verify the environment file

Open the Environment UI (top-right environment selector → Edit). Confirm that the External Secrets section shows your secret providers and mappings.
4

Update variable references (optional but recommended)

Find any {{$secrets.name.keyname}} usage in your request URLs, headers, bodies, and scripts. Replace them with the new {{name.keyname}} syntax. The old syntax still works and will continue to do so until the next major release, but Bruno marks it with a deprecation underline in the editor.From v4.2.0: Bruno provides a one-click in-app migration tool that automatically rewrites all {{$secrets.*}} references across your collection to the new syntax. You do not need to do this manually if you can wait for v4.2.0.
5

Commit the updated environment file

The migrated externalSecrets block is now in your environment .yml or .bru file. Commit it to version control so the CLI and other team members can use it.
6

Remove secrets.json (optional)

Once you have verified the migration, delete secrets.json from the collection root. Bruno no longer reads it in v4.

Step-by-step migration (CLI / CI)

1

Migrate the collection in the app first

The app migration must run before the CLI can use the new format. Open the collection in Bruno, confirm the externalSecrets block appears in the environment file, then commit and push.
2

Create a secrets credential file

Create a dotenv file with your provider credentials (never commit this file):HashiCorp Vault (token)
AWS Secrets Manager
Azure Key Vault (Service Principal)
3

Update your CLI command

Old command (pre-v4):
New command (v4+):
4

Update CI/CD pipelines

Replace secrets.json injection steps with --secrets-env-file. Store credentials in your CI secret store (GitHub Actions secrets, GitLab CI variables, etc.) and write them to a temp file before the bru run step.

Gotchas

The CLI will not run if secrets.json exists without a migrated environment file. The CLI prints a warning and continues without secrets — it does not fail hard, but requests that depend on secrets will receive empty values. Fix: open the collection in the app first. Each environment has its own externalSecrets block. In v3, all environments shared one secrets.json. In v4, each environment file declares its own secrets. If you have multiple environments (Dev, Staging, Production) pointing to different vaults or regions, update each one independently in the Environment UI. secrets.json is not automatically deleted. After migration Bruno stops reading it, but the file stays on disk. Clean it up manually once you have verified the migration and confirmed nothing else depends on it. Variable syntax change is not auto-applied to request files (until v4.2.0). The old {{$secrets.name.keyname}} syntax still resolves in v4 and will continue to work until the next major release. Bruno marks usages with a deprecation underline in the editor. You can update references manually by searching for $secrets across your collection, or wait for the v4.2.0 in-app migration tool which will rewrite all occurrences automatically with one click. runtimeVariables overrides do not bypass secret resolution. Secret variables are resolved first. If a secret and a runtime variable share the same name, the secret value takes precedence (external secrets sit above runtime vars in the precedence chain). The --secrets-env-file flag is required for AWS and Azure in CI. Unlike HashiCorp Vault (which can use --env-var for token auth), AWS and Azure credentials must be passed via --secrets-env-file. Flat --env-var flags are not read by the AWS/Azure credential resolver.

Need help?