braintrustdata/braintrust, it covers projects, datasets, functions, scores, tags, permission groups, project groups, roles, ACLs, service accounts and tokens, AI provider secrets, environment variables, automations (including retention), saved views, and MCP servers.
The Braintrust Terraform Registry entry documents every resource and data source, including their arguments. The provider’s source code, examples, and releases are in the terraform-provider-braintrust GitHub repository.
The provider manages resources inside a Braintrust organization that already exists, and doesn’t provision cloud infrastructure. To deploy a self-hosted data plane in your own cloud account, use the data plane Terraform modules.
What to manage with Terraform
Terraform works best for stable configuration that a platform team governs centrally and shares across teams or environments:- Access and identity: Permission groups, roles, ACLs, service accounts, and service tokens.
- Project scaffolding: Projects, score definitions, tags, and datasets (the containers, not their rows).
- Organization policy: AI provider secrets, environment variables, and automations, including retention.
- Frequently changing prompts and functions: Push these with the SDK or
bt functions pushso they ship with your application. Terraform doesn’t build or upload code bundles, so functions with local dependencies need the push workflow. - Data and events: Dataset rows, logs, and experiment results.
Example: Set up a support team
This example walks through a realistic configuration, from an empty directory to a workingterraform apply, that shows how the Braintrust Terraform provider’s resources fit together so you can adapt them to your own organization.
The configuration sets up Braintrust for a support team that builds a customer support bot, with:
- Production and staging projects, so changes tested in staging don’t affect production.
- Two permission groups: engineers who build in both projects, and reviewers who view results without changing anything.
- A shared prompt that triages support tickets, and a scorer that checks the prompt’s answers.
main.tf file. The complete configuration is at the end of the example.
Prerequisites
Custom permission groups and project-level permissions are only available on the Enterprise plan.
- Terraform 1.0.3 or later.
- The members you want in each group, already invited to your organization.
- A Braintrust API key or service token for your organization.
1. Install and authenticate
Terraform needs the Braintrust provider and a credential before it can change anything in your organization. Theterraform block names the provider to download from the Terraform Registry. Uncomment version and set it to the latest release so that future provider updates don’t change your configuration’s behavior unexpectedly. The provider block configures the provider. Left empty, it reads your credential from the BRAINTRUST_API_KEY environment variable.
In an empty directory, create main.tf:
main.tf
terraform init to download the provider:
2. Look up members
Permission groups identify members by user ID, not email. Thebraintrust_user data source looks up an existing member by email and returns the user ID that step 4 needs, without changing anything in Braintrust.
The code lists the engineer and reviewer emails in two variables, then looks up each email. Replace the default emails with your members’ emails. Each email must belong to a member of your organization.
main.tf
3. Create projects
In this example, the support team needs two projects: one for the live support bot, and a staging project for testing changes before they reach production. Keeping them separate also lets the team grant access to each one independently. Thebraintrust_project resource creates both.
main.tf
terraform apply fails instead of taking it over. Import the project first.
4. Create permission groups and grant access
Engineers build and change things, while reviewers only view results, so the two groups need different access to both projects. Braintrust grants access through three pieces, each with its own block in the provider:- Permission groups (
braintrust_group) let you grant access to several members at once. - Roles (
braintrust_roledata source) are sets of permissions. Braintrust includes built-in roles such asEngineerandViewer. - ACLs (
braintrust_acl) grant one group one role on one object, such as a project.
Engineer role and the Support reviewers group the Viewer role, with one ACL for each group on each project:
main.tf
Engineer or Viewer, looking up the role by name fails. Look it up by id instead.
If a group with the same name already exists, terraform apply fails instead of taking it over. Import the group first, or use a different name.
Grant access to every project
These ACLs cover only the two support projects. To grant a group a role on every project in your organization, including projects created later, set object_type to org_project and object_id to your organization ID. Any project’s org_id attribute holds that ID:
5. Add a prompt and a scorer
The support bot needs a prompt that triages tickets and a scorer that checks the prompt’s answers. Both change rarely and are shared across teams, which makes them a good fit for Terraform. Thebraintrust_function resource manages prompts and functions such as scorers, tools, and preprocessors. Two arguments describe the function, and both take JSON strings in the shape the Braintrust API accepts:
function_data_jsonsets the function’s type, such aspromptorcode.prompt_data_jsonsets a prompt’s messages and model. Only prompts use it.
jsonencode() function turns Terraform values into these JSON strings, so you don’t have to write raw JSON.
The code creates a prompt that classifies a ticket as billing, bug, or how-to. It also creates a scorer that returns 1 if the prompt’s answer is one of those categories, and 0 if it isn’t:
main.tf
bt functions push, use the braintrust_function data source.
If a function with the same slug already exists in the project, terraform apply fails instead of overwriting it. Import the function first, or use a different slug.
6. Apply and verify
With the configuration complete, Terraform can create everything in Braintrust.terraform plan shows what Terraform will create, change, or delete, without changing anything. terraform apply shows the same plan, asks you to confirm, and then makes the changes.
- The projects, in your organization’s project list
- The groups, in Settings > Permissions
- The prompt and scorer, in the Support bot project’s Prompts and Scorers pages
terraform apply again to update Braintrust. Terraform records what it created in a local state file, which can hold secrets. Before you manage your organization’s real configuration, see Use the provider in production.
Complete configuration
The completemain.tf for this example:
main.tf
Use the provider in production
The example above runs from your machine with a personal API key, a local state file, and resources that don’t exist yet. Managing your organization’s real configuration also means planning for:- The credential your CI pipeline uses, and the extra requirements for managing service tokens.
- Your organization’s API URL, if it doesn’t use the US data plane.
- Resources that already exist in Braintrust.
- Where to store state, since it holds secrets.
- How changes roll out to an organization people are using.
Authenticate in CI
The example authenticates with your personal API key. In production, run Terraform from a CI pipeline with a service token instead. A service token belongs to a service account rather than a person, so pipeline runs don’t depend on any one member’s access. Like any credential, it can change only what its account has permission to change. The provider accepts the token in either of two ways:BRAINTRUST_API_KEYenvironment variable (recommended): Store the token in your CI system’s secret store and expose it to Terraform asBRAINTRUST_API_KEY. Your configuration doesn’t change.api_keyargument: Setapi_keyin theproviderblock from a variable, never from a key written in the file. Supply the variable’s value outside version control, for example with aTF_VAR_braintrust_api_keyenvironment variable.
api_key argument, mark the variable sensitive to hide the value in Terraform’s output, and ephemeral to keep it out of state and plan files. ephemeral requires Terraform 1.10 or later.
Manage service tokens
Thebraintrust_service_token resource creates service tokens, but it requires a more privileged credential than other resources. User API keys can’t create service tokens, so the resource must use a provider block that authenticates with a service token whose account:
- Has organization-owner permissions, or is an owner of a project group.
- Holds all of the current permissions of the service account that the new token belongs to, including permissions outside any project group.
braintrust_service_token resources use:
- Keep your existing
provider "braintrust"block. It authenticates with your usual credential, and every resource uses it by default. - Add a second
provider "braintrust"block with analias, which names the block, and set itsapi_keyto the privileged service token. - On each
braintrust_service_tokenresource, setprovider = braintrust.<alias>so that resource uses the second block.
Set the API URL
The provider sends requests tohttps://api.braintrust.dev by default. If your organization uses the EU data plane or a self-hosted data plane, set api_url in the provider block or the BRAINTRUST_API_URL environment variable:
Import existing resources
Importing links a resource that already exists in Braintrust, such as a project someone created in the UI, to aresource block in your configuration. Terraform then manages it as if it had created it: terraform apply updates it to match your configuration, and terraform destroy deletes it.
Without an import, terraform apply usually fails when it tries to create a resource that already exists. Environment variables and AI secrets are the exception, as Make changes safely explains.
You can import every resource except braintrust_service_account and braintrust_service_token.
1. Find the import ID
For most resources, the import ID is the resource’s Braintrust ID. These resources use a composite ID instead, made of several IDs joined by slashes:
2. Import the resource
Terraform provides two ways to import:
- Import block
- Import command
On Terraform 1.5 or later, add an To have Terraform write the
import block with the resource’s ID and the resource block to link it to, then run terraform apply. The import shows up in terraform plan for review, like any other change.imports.tf
resource block for you, add only the import block and run terraform plan -generate-config-out=generated.tf. Review the generated file before you apply it.Secure the state file
Terraform records every resource it manages in a state file, including these secret values in plaintext:braintrust_service_tokenkeysbraintrust_ai_secretcredentialsbraintrust_env_varvalues
terraform plan and terraform apply output, but doesn’t keep it out of state. Store state in a remote backend that encrypts it at rest and limits who can read it. Use a backend that supports state locking, so that two runs can’t change state at the same time.
Make changes safely
Some provider behaviors affect what happens when you apply changes. For example, creating a resource that already exists usually fails, and changing an ACL removes access while Terraform replaces it. Review the following behaviors before you make changes.Creating a resource that already exists fails
Creating a resource that already exists fails
If a project, dataset, function, score, tag, group, project group, role, ACL, automation, view, or MCP server with the same name or slug already exists,
terraform apply fails without changing it. Import it first, or use a different name.In provider v0.0.6 and earlier, terraform apply takes over an existing group, role, or ACL instead of failing, and overwrites an existing function.Environment variables and AI secrets overwrite existing values
Environment variables and AI secrets overwrite existing values
If an environment variable or AI secret with the same name already exists,
terraform apply overwrites its value instead of failing, even after an import.Terraform reverts most changes made outside it
Terraform reverts most changes made outside it
If someone edits a Terraform-managed resource in the Braintrust UI, the next
terraform apply usually restores the configured values. Terraform can’t tell when someone changes an environment variable value or AI secret credential outside Terraform, because the API never returns those values. A change made in the Braintrust UI stays in place until you change the value in your configuration and apply it.Changing an ACL briefly removes access
Changing an ACL briefly removes access
Terraform replaces an ACL on any change, and by default it deletes the old ACL before creating the new one. If the create fails, the access stays removed until you fix the configuration and apply again. To create the new ACL first, add Terraform’s
create_before_destroy lifecycle setting to each braintrust_acl resource.Service tokens can't be imported
Service tokens can't be imported
A token’s secret is available only when it’s created. If you lose the state that holds a token, delete the token in Braintrust and create a new one.
Next steps
- Browse the resource and data source reference on the Terraform Registry.
- Adapt a complete configuration, such as roles and groups for a multi-team organization or a CI pipeline with per-environment projects, from the provider’s examples.
- Follow provider releases and browse the source in the
terraform-provider-braintrustGitHub repository. - Control access to learn what each permission and built-in permission group grants.
- Manage organizations to invite members and create API keys and service tokens.