BTST
PluginsQuickstartDocs
Live Blog

From research to product evaluation

Evaluating a publishing workflow for an app you already own?

See what the BTST Blog plugin adds to an existing React or Next.js app
BTST

Open-source TypeScript features for the React application, data, and deployment you already own.

Released plugins

  • Blog
  • AI Chat
  • CMS
  • Form Builder
  • UI Builder
  • Kanban
  • Comments
  • Media
  • Route Docs
  • OpenAPI
  • Better Auth UI

Resources

  • Quickstart
  • Documentation
  • All plugins
  • Live Blog
  • GitHub (opens in a new tab)
© 2026 BTST. Open source under the MIT License.
AI Chat
September 11, 2026ReactMedia

React Media Library Uploads: Connect Storage, Records, and Permissions

Choose a media upload flow, distinguish asset records from public file URLs, and diagnose partial uploads before using images in published pages.

React Media Library Uploads: Connect Storage, Records, and Permissions

A React media library manages two connected things: file bytes in storage and asset records in a database. Choosing an upload component is only part of the integration. You also need a storage flow, a retrieval policy, and a way to handle incomplete uploads.

For a blog feature image, the file might live in object storage while the database record holds its URL, filename, type, dimensions, and folder association. The article selects an asset through a picker. Uploading the bytes alone does not prove the asset is registered, and registering a URL does not prove the image loads.

Choose where upload bytes travel#

BTST Media 3.0.0 exposes three storage adapter shapes. Their request paths differ:

AdapterUpload flowIntegration concern
LocalBrowser sends bytes to the application backendDurable disk, backups, and serving uploaded files
S3-compatibleBackend issues a presigned URL; browser uploads to storageBucket configuration, CORS, expiry, and the public base URL
Vercel BlobClient-token flow and a provider completion callbackServer credentials, signed callback handling, and asset finalization

These flows are defined by the released storage interfaces. Configure one through the Media plugin documentation.

Choose local storage only when your deployment gives it an appropriate persistent location. A writable development directory is not proof that a production instance retains files across replacements or shares them with other instances. For direct browser uploads, test against the real storage origin; success through a local application proxy does not establish correct CORS behavior.

Keep asset permissions separate from file visibility#

Protect library browsing, upload authorization, record updates, and deletion using the application's backend policy. BTST 3.0.0 requires a configured server auth adapter on the backend stack to enforce permission rules; that authorization is opt-in. Then separately decide who can fetch an asset's URL.

The released adapter interfaces use public asset URLs. Hiding a file from the library does not make a known public URL private. If the requirement is confidential documents, evaluate an authenticated delivery or signed-download design explicitly; do not treat the standard public media workflow as proof of private file delivery.

The same distinction applies to folders. An organizational folder is not automatically an access boundary. For a multi-tenant application, verify both the server-side record scope and the storage delivery policy using two tenants before accepting confidential uploads.

Enforce constraints before accepting an asset#

BTST Media accepts backend configuration for maxFileSizeBytes, allowedMimeTypes, and trusted URL prefixes. The released plugin configuration defines those controls. They complement the operation authorization rules.

For a feature-image workflow, permit the image formats and maximum size your product needs. Keep storage credentials on the server. Do not let a caller register an arbitrary remote URL merely because the picker normally sends a trusted one.

File extensions and client-reported MIME types are not complete file-content validation. If the application needs malware scanning, document parsing, or transformation guarantees, add and verify those steps as part of its ingestion workflow. Avoid advertising them as properties of an upload button.

Diagnose partial success in order#

When an editor says an upload succeeded but the image is missing, check each boundary:

  1. Did the server authorize the upload or token request?
  2. Did storage accept the bytes?
  3. Did completion or registration create the expected asset record?
  4. Does an ordinary browser request to the stored URL load the file?
  5. Does the picker return that asset, and did the article save the selected URL?

This sequence separates storage errors from database or rendering errors. A failed final step should not automatically trigger another upload of the same file. Inspect the existing object and record before retrying.

Also test interrupted uploads, rejected MIME types, oversized files, and a failed storage deletion in a disposable environment. Observe whether the library and storage remain consistent. Plan how operators identify orphaned objects and stale records; do not assume every external storage effect shares the database transaction.

Verify the image where readers see it#

After selecting a feature image, check the published article header, listing card, and social metadata. Test a narrow viewport as well as desktop: a technically valid URL can still produce an unusable crop or an image that is too large to load comfortably.

The Media plugin overview shows the library and picker boundary. Combine it with the Blog-versus-CMS guide when deciding which editorial workflow should consume the assets. The completion criterion is a stored, authorized, retrievable asset used correctly by the published page.

In This Post

Choose where upload bytes travelKeep asset permissions separate from file visibilityEnforce constraints before accepting an assetDiagnose partial success in orderVerify the image where readers see it