Skip to content

Migrating from S3

What to change when you move code or pipelines from Amazon S3, Cloudflare R2 or MinIO to Shelby.

Most code that works with S3 works with Shelby after a configuration change. This page lists that change, then the S3 features worth checking your code for.

1. Change the client configuration

SettingValue
Endpointhttps://s3.beta.shelby.xyz
Access key IDYour access key ID (starts with SHLB)
Secret access keyYour access key's secret
BucketThe bucket's name, for example shelby-managed-account-1
Regiondefault
AddressingPath-style

Find your bucket name, and an access key ID and secret for that bucket, at console.shelby.xyz. Each access key reaches only its own bucket. Your default project already has a bucket, so there's nothing to create.

For a boto3 client, the change looks like this:

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.beta.shelby.xyz",  
    aws_access_key_id=SHELBY_ACCESS_KEY_ID,  
    aws_secret_access_key=SHELBY_SECRET_ACCESS_KEY,  
    region_name="default",  
    config=Config(
        s3={"addressing_style": "path"},  
        request_checksum_calculation="when_required",  
    ),
)

Each quickstart shows the same change for its client.

2. Check for features Shelby handles differently

Search your code for these calls and settings. Each one needs a change, or a decision.

If your code usesOn ShelbyWhat to do
CopyObject, aws s3 mv, s3.copyNot supportedDownload and upload again
x-amz-meta-* user metadata over 2 KBRejected with MetadataTooLarge, as on S3Keep larger metadata in your application or database
Presigned download URLs (generate_presigned_url, getSignedUrl, aws s3 presign)Supported for GET and HEAD, for up to 7 daysSign with region default. In JavaScript, also set responseChecksumValidation: "WHEN_REQUIRED" on the client. response-cache-control and response-expires are refused. See Presigned URLs.
Presigned uploads, or uploads from a browserNot supported (no presigned PUT, and you can't configure CORS)Upload from your server
If-Match for optimistic concurrencyNot enforced yetCoordinate writers in your application. Create-only writes with If-None-Match: * do work.
Conditional GET for caching (If-None-Match, If-Modified-Since)IgnoredEach read downloads the full object
Lifecycle rules, object expiryNot availableDelete objects yourself when you no longer need them
VersioningNot availableWrite each version to its own key, for example model/v12/weights.bin
Tags, storage classesIgnoredEncode anything you need in the key
x-amz-checksum-*Accepted, not verifiedUse Content-MD5, which Shelby verifies, or compare SHA-256 after download
A paginator with PageSize over 1,000RejectedUse 1,000 or less
Several buckets, or CreateBucket in codeBuckets are created in the console, and each access key reaches only its own bucketCreate the buckets in the console, and make a client for each bucket with that bucket's access key
Listing right after writingA new object can take a few seconds to appearRetry the listing, or track the keys you wrote
DeleteObjects from the AWS SDK for JavaScriptNot recognised yet; nothing is deletedDelete keys one at a time with DeleteObjectCommand

3. Copy your existing data

rclone can copy straight from S3, R2 or MinIO into Shelby. Configure a remote for the source as usual, then:

rclone copy source:my-bucket "shelby:$SHELBY_BUCKET" --checksum --progress

rclone streams each object through your machine, because Shelby can't copy server-side. Run it close to the source (for example, in the same cloud region) to keep transfer costs down.

4. Verify

After copying, compare the two sides:

rclone check source:my-bucket "shelby:$SHELBY_BUCKET" --one-way

rclone check compares sizes, and MD5 hashes wherever both sides have them. Large files that rclone uploads in parts (over 200 MiB by default) have no whole-file MD5, so for those it compares size only. For a byte-for-byte check, add --download.

The migrate-from-s3 recipe runs steps 3 and 4 end to end on a public dataset. It copies with rclone, checks with rclone check, then runs the same DuckDB query against both sides and compares the results.