Route dx0's metadata storage into an S3 bucket in your own AWS account. Use this when compliance, data residency, or security policy requires that client data stays within infrastructure you control.
How it works
dx0 indexes Salesforce metadata (Apex, Flows, components, etc.) and stores it in S3 to power search and impact analysis. By default that S3 bucket is in dx0's managed AWS infrastructure. This feature lets you substitute your own bucket.
Access is granted via AWS cross-account IAM role assumption (AssumeRole). dx0 requests temporary credentials scoped to your bucket each time it needs to read or write — no long-lived keys are exchanged, and credentials expire after one hour. You can revoke access at any time by deleting the IAM role.
Prerequisites
AWS account with permission to create CloudFormation stacks, S3 buckets, and IAM roles
AWS CLI installed, or access to AWS Console
Workspace admin role in dx0
Step 1: Deploy the CloudFormation stack
Go to Configuration → Settings → Storage in dx0. You'll find a ready-to-copy CLI command with your Workspace ID already embedded.
Run the command in AWS CloudShell or your local terminal:
aws cloudformation create-stack \ --stack-name dx0-metadata-storage \ --capabilities CAPABILITY_NAMED_IAM \ --parameters \ ParameterKey=ExternalId,ParameterValue=YOUR_WORKSPACE_ID \ ParameterKey=BucketName,ParameterValue=dx0-metadata-YOUR_WORKSPACE_ID \ --template-body "$(curl -s https://api.dx0.io/byob/template)"
The bucket name defaults to dx0-metadata-{workspaceId}. You can change it before running — bucket names must be globally unique in AWS.
If you prefer the AWS Console: Download the template (curl -o dx0-template.yaml https://api.dx0.io/byob/template), open CloudFormation → Create Stack, upload the file, and fill in the two parameters: your Workspace ID as ExternalId, and your chosen bucket name.
What the template creates
The stack creates two resources:
S3 Bucket — AES-256 encrypted, all public access blocked, with a lifecycle rule to clean up incomplete multipart uploads
IAM Role (
dx0-metadata-access) — Scoped tos3:ListBucket,s3:GetObject,s3:PutObject, ands3:DeleteObjecton your bucket only. The trust policy restricts access to dx0's AWS account and uses your Workspace ID as the ExternalId to prevent confused deputy attacks.
You can view the full template at https://api.dx0.io/byob/template.
Wait for the stack to reach CREATE_COMPLETE before continuing:
aws cloudformation describe-stacks --stack-name dx0-metadata-storage --query 'Stacks[0].StackStatus'
Step 2: Get the stack outputs
aws cloudformation describe-stacks \ --stack-name dx0-metadata-storage \ --query 'Stacks[0].Outputs' \ --output table
You'll need three values:
Output | Example |
RoleArn |
|
BucketName |
|
Region |
|
Step 3: Connect the bucket in dx0
In Configuration → Settings → Storage, paste the Role ARN, Bucket Name, and Region from the stack outputs. The Bucket Name field is pre-filled with the default — update it only if you customized it before deploying.
Type the confirmation phrase: I understand my data will be stored externally
Click Connect Bucket. dx0 validates the connection by assuming the role and performing a test operation. If validation fails, check the troubleshooting section below.
Step 4: Re-index your orgs
After connecting, your existing metadata index is still in dx0's managed storage. It doesn't migrate automatically. For this reason, you must delete any org connected to dx0 and re-authenticate to them from scratch.
What gets stored
dx0 stores one zip file per Salesforce metadata type per connected org:
{workspaceId}/ {orgId}/ ApexClass.zip ApexTrigger.zip Flow.zip LightningComponentBundle.zip ...
These contain raw Salesforce metadata retrieved during indexing. No credentials, tokens, or personally identifiable information is stored in the bucket.
Disconnecting
To revert to dx0's managed storage:
In dx0, go to Configuration → Settings → Storage and click Disconnect
Delete the CloudFormation stack in AWS:
aws cloudformation delete-stack --stack-name dx0-metadata-storage
Disconnecting in dx0 immediately stops routing new requests to your bucket. Your existing data in the bucket is not deleted — clean it up from AWS directly. Re-index your orgs after disconnecting so dx0 rebuilds the index in its own storage.
If CloudFormation fails to delete the stack because the bucket isn't empty, either empty the bucket first or update the stack template to add DeletionPolicy: Delete with EmptyBucketOnDelete.
Troubleshooting
"Access Denied" when saving bucket configuration
Confirm the CloudFormation stack reached
CREATE_COMPLETECheck that the Role ARN was copied exactly (no extra whitespace)
Verify the ExternalId parameter in the stack matches your dx0 Workspace ID exactly
Indexing fails after connecting
Confirm the IAM role still has
s3:PutObjectpermission (check if the stack was modified after deployment)Verify the bucket hasn't been manually deleted from S3
Check for any bucket policies added after deployment that might block cross-account access
Search returns no results after connecting
Re-index your orgs — existing data is not automatically migrated to your bucket
Check the indexing status on each org in Connected Orgs to confirm it completed without errors
FAQ
Does dx0 have standing access to my AWS account? No. dx0 assumes the IAM role to get temporary credentials valid for one hour, scoped to your bucket only. There are no standing credentials and no access to any other AWS resources.
Can I use an existing S3 bucket? Yes. Remove the MetadataBucket resource from the CloudFormation template and update the IAM policy to reference your existing bucket's ARN. Ensure the bucket has encryption enabled and public access blocked before connecting.
Can I use a bucket in any AWS region? Yes. Choose a region that meets your data residency requirements, or one close to your team for better search performance.
Is data encrypted in the bucket? The CloudFormation template configures AES-256 server-side encryption (SSE-S3) by default. If your organization requires KMS encryption, modify the template to use aws:kms with your own KMS key before deploying.
What happens if I delete the CloudFormation stack while dx0 is indexing? The in-progress job will fail. You can reconnect a bucket and re-index, or disconnect and fall back to dx0's managed storage.
Practical scenarios
Client has data residency requirements in the EU. Deploy the CloudFormation stack in eu-west-1 (or whichever EU region satisfies the requirement). Connect the bucket in dx0 and re-index. All metadata stays in that region from that point forward.
Your firm's security policy requires all data to stay in vendor-controlled accounts. Use this feature to ensure Salesforce metadata never leaves your AWS account. Combine with AWS CloudTrail to produce an audit log of every time dx0 reads or writes to the bucket.
You're ending an engagement and need to confirm data was removed. Disconnect the bucket in dx0, then empty and delete it from AWS. CloudTrail will show the last AssumeRole event from dx0's account, which you can use as evidence of access termination.
You want to verify the integration is working. After re-indexing an org, open the bucket in the S3 Console — you'll see zip files organized by workspace and org ID. You can also check CloudTrail for AssumeRole events from dx0's account.