Skip to main content

API guide

UploadThing vs Cloudflare R2 vs S3 for Next.js 2026

Compare UploadThing, Cloudflare R2, and Amazon S3 for Next.js file uploads in 2026: current pricing inputs, compatibility boundaries, and migration checks.

·APIScout Team
Share:
Hero image for UploadThing vs Cloudflare R2 vs S3 for Next.js 2026

Choosing file infrastructure for Next.js means choosing who owns the upload workflow, storage contract, security checks, and cost model. UploadThing provides an application-focused file-route workflow. Cloudflare R2 exposes an S3-compatible subset with different pricing and compatibility boundaries. Amazon S3 provides AWS storage classes and integrations. The right fit depends on the workflow you need to operate.

TL;DR verdict

Use conditional selection criteria:

  • Choose UploadThing when its documented file routes, middleware, completion hooks, and Next.js adapters match the application workflow you want.
  • Choose R2 when its current pricing and S3-compatible with documented exceptions interface fit the required operations.
  • Choose S3 when the required storage classes and AWS integrations are part of the design.

Compare documented compatibility and required features first, then recalculate every scenario from current inputs for the actual workload.

API fit matrix

Decision areaUploadThingCloudflare R2Amazon S3
Next.js integrationDocumented Next.js App Router adapters and file routesAWS SDK configured for the R2 endpointAWS SDK configured for the target AWS region
Upload authorizationFile-route middlewareApplication issues constrained direct-upload credentials or URLsApplication issues constrained direct-upload credentials or URLs
Completion workflowUpload-completion hookApplication completes and records the object workflowApplication completes and records the object workflow
Multipart controlVerify documented and installed SDK behaviorS3 multipart operations supportedNative multipart operation set documented
Storage choiceManaged through the product contractR2 object storageS3 storage classes
Cost modelRe-open the current plan pageStorage and operation units; internet egress listed as freeRegion, class, requests, duration, and transfer path affect total

UploadThing: application-level file routes

UploadThing documents file routes that define accepted file types and route options. Middleware runs before the upload workflow is authorized, and an upload-completion hook can persist application metadata.

import { createUploadthing, type FileRouter } from 'uploadthing/next';

const f = createUploadthing();

export const uploadRouter = {
  imageUploader: f({ image: { maxFileSize: '4MB' } })
    .middleware(async ({ req }) => {
      const user = await requireUser(req);
      return { userId: user.id };
    })
    .onUploadComplete(async ({ metadata, file }) => {
      await saveUpload({ userId: metadata.userId, key: file.key });
    }),
} satisfies FileRouter;

Current UploadThing SDKs expose the app-scoped file URL as file.ufsUrl. The official public-file pattern is https://<APP_ID>.ufs.sh/f/<FILE_KEY>. Verify the installed package's returned fields and treat its delivery behavior as part of the product contract.

UploadThing SDKs are open source, but this guide keeps no frozen popularity count. Repository counters are volatile and do not decide architecture fit.

The file-route docs include option-specific history labels, such as features introduced in a particular release. Treat that as a feature-level version annotation and verify installed package version before using the option. The package does not freeze an overall SDK release.

Auth and upload matrix

StageUploadThingR2 or S3Required control
Request startsFile-route middleware checks application identityServer checks identity before issuing upload authorityBind user and tenant before creating an upload
Upload authorityProduct workflow returns the allowed upload pathPresigned operation or temporary credentialLimit key, method, content type, size, and expiry where supported
Client sends bytesProduct adapter follows the route contractClient uploads to object storageNever expose long-lived storage credentials
CompletionCompletion hook updates application stateClient/server completes and records the objectVerify ownership and final object state
CleanupFollow product lifecycle behaviorAbort or expire incomplete workReconcile abandoned uploads and application records

R2: compatible surface with explicit boundaries

Cloudflare documents the account endpoint as:

https://<ACCOUNT_ID>.r2.cloudflarestorage.com

For AWS SDK configuration, the region is auto. R2 implements the S3 API with documented additions and omissions, so review the compatibility page for every operation, header, checksum, and feature the application uses.

import { S3Client } from '@aws-sdk/client-s3';

const r2 = new S3Client({
  region: 'auto',
  endpoint: r2EndpointFromTrustedConfig,
  credentials: r2CredentialsFromServerOnlyConfig,
});

The endpoint and credentials belong in trusted server configuration. Never accept an account endpoint or bucket destination directly from an untrusted client.

SDK quality table

ConcernUploadThingR2S3
Next.js adapterFirst-party documented adapterAWS SDK in a Next.js server routeAWS SDK in a Next.js server route
Type flowFile-router types connect route and clientApplication owns request/response typesApplication owns request/response types
Error accessVerify adapter error surfacePreserve SDK status and request metadataPreserve SDK status and request metadata
Multipart uploadVerify exact SDK/product behaviorReview supported multipart operationsReview documented multipart operations
Upgrade gateCheck option annotations and package versionRecheck compatibility pageRecheck SDK and service documentation

Current pricing inputs

Cloudflare's R2 Standard pricing page, accessed 2026-08-22, lists:

  • storage at $0.015 per GB-month;
  • Class A operations at $4.50 per million requests;
  • internet egress as free; and
  • a monthly Standard free tier of 10 GB-month, 1 million Class A requests, and 10 million Class B requests.

These are inputs, not a finished application bill. Operation mix, storage duration, transformations, delivery products, taxes, and other services can change the total.

UploadThing's official pricing page currently renders free, 100GB, and usage-based plan rows. Because these inputs are volatile, reopen the page and date any copied figure; this guide does not freeze UploadThing scenario totals. S3 pricing varies by region, storage class, request class, storage duration, and transfer path. Recalculate every scenario from the current official pages rather than carrying forward old sample totals.

Quota and capacity box

Before implementation, record:

  1. maximum object and request sizes required by the product;
  2. expected object count and storage duration;
  3. upload and download request mix;
  4. multipart thresholds and part limits;
  5. concurrency and retry behavior;
  6. expiration and cleanup rules; and
  7. any account or plan quotas confirmed in the current console or documentation.

Do not infer capacity from a marketing label; verify feature availability before implementation.

Multipart workflows

R2 supports multipart upload operations through its documented S3-compatible surface. Amazon S3 documents create, upload-part, complete, abort, and list operations. A production workflow should persist the upload identifier, validate part numbers and ETags, complete explicitly, and abort incomplete multipart uploads after the application's chosen retention window.

interface MultipartSession {
  ownerId: string;
  objectKey: string;
  uploadId: string;
  createdAt: string;
}

Large-file design also needs retry and integrity policy, so measure with the target workload instead of publishing setup-time or latency claims.

Integration risk box

RiskConsequenceControl
S3-compatible assumption exceeds documented subsetMigration or runtime failureInventory every required operation and header
Presigned authority is too broadUnauthorized writes or unexpected costBind object key, expiry, content constraints, and identity
Database row is created before object completionBroken application referencesUse pending state and completion reconciliation
Incomplete multipart sessions accumulateStorage and operational residueSchedule explicit abort and audit
Price model is copied from an old articleIncorrect purchasing decisionRecalculate every scenario from live inputs
Application cannot change providersMigration becomes a product rewriteStore provider-neutral object identity and metadata

Migration decision: S3 to R2

The AWS SDK can target R2's documented endpoint, but a safe migration is a compatibility review, not a string substitution.

  1. Inventory APIs, headers, checksums, event flows, lifecycle rules, storage classes, and delivery paths in use.
  2. Compare each requirement against the current R2 compatibility page.
  3. Create the destination bucket and server-side credentials.
  4. Copy a representative object set and verify metadata and checksums.
  5. Dual-read or stage a controlled cutover if the application requires it.
  6. Update public delivery and cache behavior separately from storage writes.
  7. Reconcile object counts and application records.
  8. Keep rollback criteria until new writes and reads are verified.

Cloudflare's S3 compatibility page had a current documentation date of July 31, 2026 and states that implementation is still in progress. The pricing page was updated August 7, 2026. Recheck both before a migration.

Source-backed evidence

UploadThing

Official docs support Next.js adapters, file routes, middleware, completion hooks, and option-level history. The official repository supports SDK source provenance.

Cloudflare R2

Official docs support the current pricing units, endpoint form, auto region, compatibility caveats, and multipart operations.

Amazon S3

Official pages support the storage-class, pricing-variable, and multipart-operation distinctions used here.

Editorial limits

The matrix, migration checklist, and security controls are implementation guidance. Validate them in the target account, package version, workload, and threat model.

Methodology

APIScout reviewed the twelve official sources below on 2026-08-22. Unsupported comparative totals, popularity counters, setup times, latency and savings claims, storage-internal assumptions, and undocumented product limits were removed. Pricing and availability remain volatile.

Source-backed FAQ

Is R2 interchangeable with S3?

Not without review. R2 implements an S3-compatible surface with documented omissions and additions. Compare the exact operations and headers your application uses.

Which option has the lowest cost?

That depends on storage duration, requests, transfer path, product plan, and adjacent services. Use current account-specific inputs and recalculate costs from current inputs.

Does UploadThing remove application authorization work?

No. Its middleware gives the application a place to enforce identity and policy. The application still owns user, tenant, and business authorization.

What should a multipart design retain?

Retain ownership, object key, upload identifier, completed parts, expiry, and cleanup state. Test completion, retry, and abort paths.

Sources

Compare the storage APIs directly on APIScout.

{/* Sources: file-r2-multipart, file-r2-pricing, file-r2-s3, file-s3-classes, file-s3-multipart, file-s3-pricing, file-uploadthing-docs, file-uploadthing-nextjs-app-router, file-uploadthing-pricing, file-uploadthing-repo, file-uploadthing-routes, file-uploadthing-working-files. Claims: apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:pricing_or_plan, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:downloads_stars_forks, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:release_version_status, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:compatibility_integrations, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:product_capabilities, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:performance_benchmarks, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:ranking_popularity_superlative, apiscout:uploadthing-vs-cloudflare-r2-vs-s3-nextjs-2026:availability_or_provider_status. */}

The API Integration Checklist (Free PDF)

Step-by-step checklist: auth setup, rate limit handling, error codes, SDK evaluation, and pricing comparison for 50+ APIs. Used by 200+ developers.

Join 200+ developers. Unsubscribe in one click.