Cloudflare R2 holds a clear lead as a cost-effective storage choice with zero egress fees. Amazon remains the primary recommendation for overall file storage and foundational scalability.
The "best" setup depends on whether you want a pure infrastructure object store (lowest cost, maximum control) or a specialized developer platform/API (handles resizing, uploading widgets, and CDNs out of the box).
Category 1: The Industry Standard (Raw Object Storage + API)
Best for: General-purpose storage, full control, lowest cost, and standard backend SDK integration.
Amazon S3 (Simple Storage Service)
The Lowdown: The undisputed heavyweight. Almost every major cloud service integrates with S3 or an S3-compatible API.
Why it's great: Virtually infinite scalability, extreme reliability (99.999999999% durability), and granular security via IAM and Presigned URLs (allowing direct-to-cloud browser uploads without routing gigabytes through your server).
Check it out: Amazon S3
Google Cloud Storage (GCS)
The Lowdown: Google’s equivalent to S3, widely praised for fast global edge performance and intuitive bucket management.
Why it's great: Excellent global network performance and seamless integration with Firebase and Google Cloud Run/Functions.
Check it out: Google Cloud Storage
Cloudflare R2
The Lowdown: S3-compatible object storage with zero egress fees (meaning no charges for downloading or serving data out).
Why it's great: If your app serves a high volume of user-uploaded files back to the public, R2 saves a massive amount of money compared to AWS egress bandwidth pricing.
The Lowdown: The gold standard for dynamic image and video manipulation.
Why it's great: Instead of writing custom image-processing microservices, Cloudinary's API handles uploads, auto-formats to modern web standards (WebP, AVIF), crops on the fly via URL parameters, and delivers via global CDNs.
The Lowdown: A modern, incredibly developer-friendly file upload wrapper specifically built for the TypeScript/Next.js/Full-stack ecosystem.
Why it's great: Radically cuts down boilerplate, offering end-to-end type safety for file uploads from client to server.
Check it out: Uploadthing
Recommendation Summary
Go with Amazon S3 or Cloudflare R2 if you are building a general file vault, document manager, or want maximum cost efficiency and standard S3 API compatibility.
For storing user-uploaded files, my default recommendation is Amazon S3 for storage plus direct-to-storage uploads using presigned URLs. If you're building a web or mobile app and want less infrastructure to manage, Supabase Storage or Cloudflare R2 may be a better fit.
The key architectural decision is to separate the upload API (how files get into your system) from the storage service (where files live). For most applications, your backend should authorize uploads, while the client uploads file bytes directly to storage instead of routing large files through your server.
Best options at a glance
1. Amazon S3
(Best general-purpose default)
Reliable, flexible object storage with a mature ecosystem, lifecycle policies, and extensive infrastructure integrations. Use presigned URLs for direct uploads.
Best for: SaaS products, documents, backups, and growing applications.
Combines file storage with Supabase authentication, database policies, SDKs, and image transformations. It supports resumable uploads for greater reliability with large files.
Best for: startups, Next.js apps, and products already using Supabase.
A higher-level upload service that simplifies upload endpoints and frontend integration, particularly in TypeScript and React projects. It's an abstraction over the storage workflow rather than a direct substitute for every object-storage capability.
Best for: teams that want to ship upload functionality quickly.
These are architectural recommendations, not a universal price ranking. Total cost depends on file size, storage volume, download traffic, request volume, and required security controls.
Recommended upload architecture
1. Browser or mobile app
User selects a file
2. Your backend
Authenticate user, validate limits, issue a short-lived upload URL
3. Object storage
File uploads directly to S3, R2, or Supabase Storage
4. Your database
Store owner ID, object key, file size, status, and metadata
This approach avoids making your application server relay every file, which reduces server bandwidth and makes large uploads easier to handle. S3 and R2 both support this pattern.
Security features you should implement
Private by default: require authorization to download user files.
Unique object keys: prevent users from overwriting each other's files.
File validation: enforce size and file-type limits on the server; don't trust the extension or browser-supplied MIME type alone.
Short-lived upload URLs: treat them as bearer credentials and keep them out of logs where possible.
Post-upload verification: verify the actual object size and type before marking the upload complete. Scan potentially dangerous files before making them available.
Resumable uploads: use multipart or resumable uploads for large files and unstable connections.
My final recommendation
Start with S3 + presigned URLs if you want a flexible, long-term storage foundation. Choose Supabase Storage if you want the simplest integrated experience, or R2 if serving lots of files makes bandwidth cost a priority.
One question that would help me narrow this down: What kind of files are users uploading, and what stack are you using? For example, PDFs and documents in a Next.js app, or large videos in a mobile app. That can change which upload API is best.