This is an example of a sandbox Braintrust data plane deployment for testing infrastructure provisioning, module changes, and deployment workflows. It uses minimal instance sizes and simplified infrastructure to reduce cost and setup time.
Warning
This configuration is not suitable for workload testing or performance evaluation. The downsized instances (single reader/writer, smallest instance types) will not reflect production performance. For a deployment you can run workloads against, use the production example with appropriately sized instances.
- AWS CLI configured with access to your target account
- Terraform >= 1.10
- A separate Braintrust Organization for sandbox testing — create one here. Do not reuse your production Organization's license key, as it will affect production metrics and alerting.
- Brainstore license key from the sandbox Organization (Braintrust UI > Settings > Data Plane)
provider.tfshould be modified to use your AWS account and region.terraform.tfshould be modified to use the remote backend that your company uses. Typically this is an S3 bucket and DynamoDB table.main.tfshould be modified to meet your needs:deployment_name— must be unique per deployment in the same AWS account (max 18 chars). Usebt-yournameor similar.braintrust_org_name— your organization name from the Braintrust UI.
- Brainstore requires a license key which you can find in the Braintrust UI under Settings > Data Plane

- The recommended approach is to store the license key in AWS Secrets Manager and reference it using a Terraform data source:
Then pass
data "aws_secretsmanager_secret_version" "brainstore_license" { secret_id = "braintrust/brainstore-license-key" }
data.aws_secretsmanager_secret_version.brainstore_license.secret_stringas thebrainstore_license_keyvalue in the module. - Alternatively, you can pass the key without storing it in Secrets Manager:
- Set
TF_VAR_brainstore_license_key=your-keyin your terraform environment - Pass it into terraform as a flag
terraform apply -var 'brainstore_license_key=your-key' - Add it to an uncommitted
terraform.tfvarsor.auto.tfvarsfile.
- Set
If you're using a brand new AWS account for your Braintrust data plane you will need to run ./scripts/create-service-linked-roles.sh once to ensure IAM service-linked roles are created.
terraform init
terraform plan
terraform applyNote
The first terraform apply may fail with transient errors — ASG health check timeouts (instances still booting) or Lambda rate limits. Re-running terraform apply resolves these.
After applying, get the API URL:
terraform output
# api_url = "https://xxxxxxxxx.cloudfront.net"
To configure your Organization to use your new data plane, click your user icon on the top right > Settings > Data Plane.
Warning
If you are testing, it is HIGHLY recommended that you create a new Braintrust Organization for testing your new data plane. If you change your live Organization's API URL, you might break users who are currently using it.
Click Edit
Paste the API URL into the text field, and click Save. Leave the Proxy and Realtime URL blank.
Verify in the UI that the ping to each endpoint is successful.

Brainstore nodes require local NVMe/ephemeral storage for caching. The instance user_data script will fail if no NVMe device is found, and the module validates this at plan time.
Compatible instance families include: c8gd, c5d, m5d, i3, i4i.
Generic families without local storage (t3, m5, c5) will not work.
Since this sandbox has DANGER_disable_database_deletion_protection = true, you can destroy after emptying S3 buckets.
The Braintrust platform writes data to S3 buckets after deployment. S3 buckets with versioning enabled must have all object versions and delete markers removed before Terraform can delete them. The buckets follow the naming pattern <deployment_name>-brainstore-*, <deployment_name>-code-bundles-*, and <deployment_name>-lambda-responses-*.
Caution
Verify you are emptying the correct buckets before proceeding. Emptying the wrong buckets can result in permanent data loss. Use the AWS Console (S3 > select bucket > Empty) to manually empty each bucket.
After emptying the buckets, run terraform destroy.
If you set enable_quarantine_vpc = true, the quarantine warmup Lambda creates ~30 functions outside Terraform state. These hold ENIs in the quarantine VPC subnets that block terraform destroy. You must delete them before destroying.
Use the included cleanup script (requires uv):
# Dry run — lists quarantine Lambdas without deleting
../../scripts/delete-quarantine-lambdas <deployment_name>-quarantine
# Delete them
../../scripts/delete-quarantine-lambdas <deployment_name>-quarantine --delete
# Wait ~5 minutes for ENIs to release, then destroy
terraform destroyThe <deployment_name>-quarantine argument is the Name tag of the quarantine VPC (e.g., bt-yourname-quarantine).


