src/server/storage-fns.ts — a server function that runs exclusively on Nitro. This design keeps SUPABASE_SERVICE_ROLE_KEY off the client entirely: the browser never holds credentials, and Supabase Row Level Security policies are never bypassed from untrusted code.
How the upload workflow works
The client collects a file, wraps it inFormData, and calls the uploadImage server function. The server validates the file, uploads it to Supabase Storage using the service role key, and returns the public URL. The client stores that URL in local state and uses it for an instant preview.
Set up the avatars bucket
Before your first upload, create theavatars bucket in Supabase. Run this in your Supabase Dashboard → SQL Editor:
'avatars' with your bucket name and adjust the policy as needed.
The uploadImage server function
src/server/storage-fns.ts is the single upload entry point. It accepts a FormData body with two fields — file and bucket:
Call the upload function from a component
Pass aFormData object directly — do not JSON-encode binary data.
Show an instant preview with derived state
After a successful upload, you want to display the new image immediately — before the user saves the form — while still falling back to the existing value from the database. Use a single derived constant rather than two separate state variables:currentImg updates the moment setUploadedImg is called, without waiting for a round-trip to the database.
Validation rules
The built-inuploadImage function enforces the following:
To add content-type validation, insert a check before the upload call:
