Storage · modules/storage

Adapter scaffold

UploadThing,
contract-first.

UploadThing plugs into the same IStorageProvider port as the S3, local and Supabase adapters. The slot is a typed scaffold today — the interface is committed, so completing it is a self-contained change that leaves the rest of the app untouched.

What ships, and what you complete

Honesty first: the UploadThing adapter is a scaffold. The boilerplate baseline does not ship the UploadThing SDK as a dependency, so presignUpload / presignDownload return a typed "not yet implemented" until you drop it in. The factory soft-falls back to the null storage provider (with a warning) when UPLOADTHING_TOKEN is set but the SDK is absent, so nothing crashes at boot. The value here is the same as every other adapter slot: the IStorageProvider port is locked, so when you wire UploadThing you implement against a shape the rest of the codebase already consumes — no ripple. If you want file storage today, the S3 adapter is fully implemented and speaks to AWS, R2 and MinIO.

The storage port it plugs into

Typed scaffold

The adapter implements IStorageProvider; each method returns the same Result types as the wired providers, so the contract is the commitment.

Soft fallback

When STORAGE_PROVIDER=uploadthing but the token/SDK is missing, the factory logs a warning and returns the null provider instead of throwing.

Wired alternative

Need storage now? STORAGE_PROVIDER=s3 is production-ready and works with AWS S3, Cloudflare R2 and MinIO.

One-file swap

Because every provider shares the port, moving from S3 to UploadThing later is a composition-root change, not an app rewrite.

Configuration reference

Environment variables

  • STORAGE_PROVIDERrequired

    Set to uploadthing

  • UPLOADTHING_TOKENrequired
  • UPLOADTHING_APP_IDoptional

Where it lives

  • apps/server/src/modules/storage/infrastructure/providers/uploadthing-storage-provider.ts
  • apps/server/src/modules/storage/infrastructure/providers/index.ts

Storage behind one contract.

Start on S3 today and swap to UploadThing later without rewriting your app — the port stays the same.