Skip to content
HexaTransfer
Back to blog
Technical Deep Dives

S3-Compatible Storage Architecture for File Transfer

Build file transfer systems on S3-compatible storage. Architecture patterns, provider comparison, and performance optimization techniques.

S3-compatible storage is the backbone of most modern file transfer services because the API is universal, the pricing is competitive, and the architecture scales without managing disks. AWS S3 pioneered the model, and clones like Cloudflare R2, Backblaze B2, Wasabi, MinIO, and DigitalOcean Spaces implement the same REST interface. Building a transfer service on S3-compatible storage gives you durable object storage (11 nines in AWS's case), multipart uploads for large files, and presigned URLs for direct browser-to-storage transfers that bypass your app servers. Here's how to architect it properly.

Why the S3 API Won

The S3 API is effectively a standard. Amazon published it in 2006, and every major object storage provider implemented it to capture workloads. That means a well-written transfer service using the AWS SDK for JavaScript (aws-sdk v3) can swap between providers by changing the endpoint URL. Open-source clients like minio-js, MinIO's mc CLI, and rclone work unchanged across providers. This gives architects flexibility: start on AWS S3 for reliability, move to Cloudflare R2 for zero egress fees, or run MinIO self-hosted for data residency, without rewriting application code.

Provider Comparison for Transfer Workloads

| Provider | Storage | Egress | Free Tier | Notable | |---|---|---|---|---| | AWS S3 Standard | $0.023/GB | $0.09/GB | 5 GB, 15 GB egress/mo | 11 nines durability | | Cloudflare R2 | $0.015/GB | $0 | 10 GB, 1M reads/mo | Zero egress fees | | Backblaze B2 | $0.006/GB | $0.01/GB | 10 GB free | Bandwidth alliance with Cloudflare | | Wasabi | $0.0069/GB | $0 | None (paid only) | 90-day minimum storage | | MinIO self-hosted | Hardware cost | Your bandwidth | Open source | AGPL v3, run anywhere | | DigitalOcean Spaces | $5/mo for 250 GB | 1 TB included | None | Fixed pricing bundle |

For a transfer service where files sit briefly then get downloaded, egress dominates. Cloudflare R2 and Backblaze B2 (via Bandwidth Alliance) win on cost. AWS S3 wins on features like Intelligent-Tiering and lifecycle policies.

Multipart Upload for Large Files

The S3 multipart upload API is how transfer services handle files above 5 GB. You InitiateMultipartUpload to get an UploadId, UploadPart for each chunk (5 MB minimum, 5 GB maximum per part, 10,000 parts total), and CompleteMultipartUpload with the list of ETags. Parts can upload in parallel. Failed parts retry independently. Clients use presigned URLs for each part so uploads go directly from browser to S3, bypassing your app server entirely. Maximum object size is 5 TB in S3, which covers essentially any transfer use case.

Presigned URLs and Direct Uploads

Presigned URLs let a client upload or download directly to S3 without your servers touching the bytes. Your backend generates a URL signed with HMAC-SHA256 and AWS credentials, valid for a specified time (typically 1 to 24 hours). The client PUTs or GETs against the URL. This pattern saves serious money: your app servers don't need the bandwidth to proxy 10 GB files, and latency drops because clients hit the storage endpoint directly. CORS configuration on the bucket allows browser uploads from your origin. Use SSE-C (server-side encryption with customer-provided keys) or SSE-KMS for at-rest encryption.

Architecture Patterns for Transfer Services

A typical S3-backed transfer architecture has three tiers. The frontend runs in a browser, initiating multipart uploads and tracking chunk progress. The API backend (a small Node.js, Go, or Python service) handles authentication, metadata storage in PostgreSQL or DynamoDB, and presigned URL generation. The storage tier is the S3-compatible bucket. This architecture scales horizontally because the app tier is stateless, and the storage tier absorbs all bandwidth. Adding a CDN like Cloudflare or CloudFront in front of GET requests improves download speeds globally and reduces egress from S3.

Lifecycle Policies and Auto-Deletion

Transfer services need files to expire automatically. S3 Lifecycle rules transition objects between storage classes or delete them based on age. A rule "delete objects older than 7 days" runs daily and purges expired transfers at zero cost. Cloudflare R2 supports lifecycle rules via the Terraform provider or R2 API. For finer control, tag each object with an expiration timestamp and run a nightly Lambda that deletes based on tags. Abandoned multipart uploads should have their own rule, AbortIncompleteMultipartUpload after 1 to 7 days reclaims storage from incomplete sessions.

Performance Optimization

S3 throughput scales with prefix. AWS S3 targets 3,500 PUT/sec and 5,500 GET/sec per prefix in the bucket, and uses consistent hashing of the key's first characters to partition load. Avoid sequential key prefixes (001, 002, 003) because they hash to the same partition and create hot spots; use random prefixes or hash-based keys like a UUID's first 8 characters. Multipart uploads improve throughput for individual transfers; parallel connections across keys improve aggregate throughput. Transfer Acceleration routes uploads through the nearest CloudFront edge and can cut upload time by 50 to 500 percent for distant clients at extra cost.

Encryption Options and Their Tradeoffs

Server-side encryption comes in three flavors. SSE-S3 (or R2's default encryption) uses AES-256 with keys managed by the provider, transparent and free. SSE-KMS uses AWS KMS-managed keys, costs $0.03 per 10,000 requests plus key charges, and produces KMS audit logs useful for compliance. SSE-C accepts a customer-provided key per request, the server encrypts with it and discards the key, so the customer must supply it on every read, which is fiddly but keeps keys out of the provider's control. For true E2EE, encrypt client-side before upload using libsodium or Web Crypto's AES-GCM, then treat the stored object as opaque ciphertext.

Monitoring, Metrics, and Billing Surprises

Watch bucket metrics in CloudWatch (AWS), the R2 dashboard, or provider-equivalent tools. Key metrics: BucketSizeBytes, NumberOfObjects, AllRequests, 4xxErrors, 5xxErrors, and BytesDownloaded. Unexpected egress spikes often indicate hot-linking (someone embedded your presigned URL on a popular site) or a bot downloading in a loop. Set billing alerts at 50, 80, and 100 percent of budget. Cloudflare R2 bills differently, Class A operations (writes) at $4.50 per million, Class B (reads) at $0.36 per million, plus storage. Do the math for your traffic mix before committing.

Integration Example and HexaTransfer's Approach

A minimal transfer flow: client requests an upload token, backend generates a presigned URL for multipart upload initiation, client uploads chunks directly to S3, backend stores metadata and returns a shareable link, recipient clicks link, backend generates a presigned download URL, browser fetches and decrypts. HexaTransfer uses this pattern with client-side AES-256-GCM encryption, so the S3-compatible backend stores only ciphertext, and the encryption key never leaves the browser.

Try it at hexatransfer.com — free, no account, 10 GB max.

Send large files securely with end-to-end encryption

Transfer files up to 10 GB for free with end-to-end encryption. No account required. Your files are encrypted in your browser before upload — no one else can read them.

Send a file