# How to Update Your Application's S3 Endpoint for Quake AI

Source: https://docs.quake.ai/docs/object/migration/update-application-endpoint
Markdown: https://docs.quake.ai/docs/object/migration/update-application-endpoint.md

---

# How to update your application's S3 endpoint for Quake AI

After migrating your data, update your application code to read and write from Quake AI instead of the previous provider. Because Quake AI is S3-compatible, this is typically a configuration change, not a code rewrite.

## What changes

| Setting | Old value (AWS example) | New value (Quake AI) |
|---|---|---|
| **Endpoint URL** | `https://s3.amazonaws.com` (or omitted) | `https://object.us-east-2.rumble.cloud` |
| **Access key** | Your AWS access key | Your Quake AI access key |
| **Secret key** | Your AWS secret key | Your Quake AI secret key |
| **Region** | Varies (`us-east-1`, `eu-west-1`, etc.) | `us-east-1` (required for SigV4 compatibility) |
| **Path style** | Virtual-hosted (default on AWS) | Path style recommended |



Set the region to `us-east-1` regardless of which Quake AI region you use. This is required for AWS Signature Version 4 compatibility with Swift's S3 gateway.



## Environment variables

Many S3 SDKs read credentials and endpoint from environment variables. Set these and your application may require zero code changes:

```bash
export AWS_ACCESS_KEY_ID="YOUR_RUMBLE_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_RUMBLE_SECRET_KEY"
export AWS_ENDPOINT_URL="https://object.us-east-2.rumble.cloud"
export AWS_DEFAULT_REGION="us-east-1"
```

`AWS_ENDPOINT_URL` is supported by the AWS CLI (v2.13+), boto3 (v1.29+), and the AWS SDK for JavaScript v3. Other SDKs may require explicit configuration in code.

## SDK examples

### Python (boto3)

```python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://object.us-east-2.rumble.cloud",
    aws_access_key_id="YOUR_RUMBLE_ACCESS_KEY",
    aws_secret_access_key="YOUR_RUMBLE_SECRET_KEY",
    region_name="us-east-1",
)

response = s3.list_buckets()
for bucket in response["Buckets"]:
    print(bucket["Name"])
```

For boto3 resource interface:

```python
s3 = boto3.resource(
    "s3",
    endpoint_url="https://object.us-east-2.rumble.cloud",
    aws_access_key_id="YOUR_RUMBLE_ACCESS_KEY",
    aws_secret_access_key="YOUR_RUMBLE_SECRET_KEY",
    region_name="us-east-1",
)

for bucket in s3.buckets.all():
    print(bucket.name)
```

### Node.js (AWS SDK v3)

```javascript

const client = new S3Client({
  endpoint: "https://object.us-east-2.rumble.cloud",
  region: "us-east-1",
  credentials: {
    accessKeyId: "YOUR_RUMBLE_ACCESS_KEY",
    secretAccessKey: "YOUR_RUMBLE_SECRET_KEY",
  },
  forcePathStyle: true,
});

const response = await client.send(new ListBucketsCommand({}));
console.log(response.Buckets);
```

### Go (AWS SDK v2)

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/credentials"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
	cfg, err := config.LoadDefaultConfig(context.TODO(),
		config.WithRegion("us-east-1"),
		config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
			"YOUR_RUMBLE_ACCESS_KEY",
			"YOUR_RUMBLE_SECRET_KEY",
			"",
		)),
	)
	if err != nil {
		log.Fatal(err)
	}

	client := s3.NewFromConfig(cfg, func(o *s3.Options) {
		o.BaseEndpoint = aws.String("https://object.us-east-2.rumble.cloud")
		o.UsePathStyle = true
	})

	result, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
	if err != nil {
		log.Fatal(err)
	}

	for _, bucket := range result.Buckets {
		fmt.Println(*bucket.Name)
	}
}
```

### Java (AWS SDK v2)

```java
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3Configuration;

import java.net.URI;

S3Client s3 = S3Client.builder()
    .endpointOverride(URI.create("https://object.us-east-2.rumble.cloud"))
    .region(Region.US_EAST_1)
    .credentialsProvider(StaticCredentialsProvider.create(
        AwsBasicCredentials.create("YOUR_RUMBLE_ACCESS_KEY", "YOUR_RUMBLE_SECRET_KEY")))
    .serviceConfiguration(S3Configuration.builder()
        .pathStyleAccessEnabled(true)
        .build())
    .build();

s3.listBuckets().buckets().forEach(bucket ->
    System.out.println(bucket.name()));
```

### Terraform (S3 backend)

For storing Terraform/OpenTofu state on Quake AI:

```hcl
terraform {
  backend "s3" {
    bucket                      = "my-tf-state"
    key                         = "terraform.tfstate"
    region                      = "us-east-1"
    endpoint                    = "https://object.us-east-2.rumble.cloud"
    access_key                  = "YOUR_RUMBLE_ACCESS_KEY"
    secret_key                  = "YOUR_RUMBLE_SECRET_KEY"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
  }
}
```



The `skip_*` flags are required because Quake AI's S3 endpoint does not implement the AWS-specific metadata and credential validation APIs.



## Feature audit before switching

Before changing your application's endpoint, verify that your code does not depend on S3 features unavailable on Quake AI:

| Check for | How to find it | What to do |
|---|---|---|
| Lifecycle policy dependency | Search for `put_bucket_lifecycle_configuration` or `PutBucketLifecycleConfiguration` | Implement retention with external cron jobs |
| Event notification dependency | Search for `put_bucket_notification_configuration`, SNS ARNs, SQS ARNs, Lambda ARNs | Replace with application-level polling |
| Bucket policy dependency | Search for `put_bucket_policy` or JSON policy documents | Translate to Swift ACLs |
| S3 Select usage | Search for `select_object_content` | Download and query locally |
| Presigned URL generation | Search for `generate_presigned_url` or `getSignedUrl` | Presigned URLs are supported; no changes needed |

## Gradual cutover with dual-write

For zero-downtime migration, write to both providers during the transition:

```python
import boto3

old_s3 = boto3.client("s3", region_name="us-east-1")
new_s3 = boto3.client(
    "s3",
    endpoint_url="https://object.us-east-2.rumble.cloud",
    aws_access_key_id="YOUR_RUMBLE_ACCESS_KEY",
    aws_secret_access_key="YOUR_RUMBLE_SECRET_KEY",
    region_name="us-east-1",
)

def upload(bucket, key, body):
    new_s3.put_object(Bucket=bucket, Key=key, Body=body)
    old_s3.put_object(Bucket=bucket, Key=key, Body=body)

def download(bucket, key):
    try:
        return new_s3.get_object(Bucket=bucket, Key=key)["Body"].read()
    except Exception:
        return old_s3.get_object(Bucket=bucket, Key=key)["Body"].read()
```

Once you confirm the Quake AI endpoint is stable, remove the old provider calls and the fallback logic.

## See also

- [Plan your migration](/docs/object/migration/plan-your-migration): compatibility matrix, feature gap workarounds
- [Create S3 credentials](/docs/object/how-to/create-s3-credentials): generate access keys for Quake AI
- [Migrate from AWS S3](/docs/object/migration/migrate-from-s3): full data migration guide
