RefactKit stores avatars, organization logos, and gallery images in Supabase Storage. The upload workflow is deliberately server-side: the browser never touches Supabase directly, and theDocumentation Index
Fetch the complete documentation index at: https://docs.refactkit.com/llms.txt
Use this file to discover all available pages before exploring further.
SUPABASE_SERVICE_ROLE_KEY never leaves the server. A dedicated uploadImage server function in src/server/storage-fns.ts acts as the secure intermediary between your UI and Supabase.
How the secure upload workflow works
Client sends FormData to the server
The
ImageUpload component builds a FormData object containing the file and the target bucket name, then calls the uploadImage server function directly — no manual HTTP request needed.Server validates and uploads the file
The
uploadImage server function receives the FormData, enforces a 2 MB size limit, generates a random filename, converts the file to an ArrayBuffer, and uploads it to Supabase using the service role key:Invalidate caches after a successful upload
When a user updates their avatar or organization logo, stale data in TanStack Query and TanStack Router’s loader cache will show the old image until they refresh the page. Invalidate both caches insideonSuccess:
queryClient.invalidateQueries marks cached data as stale so the next useQuery call re-fetches. router.invalidate() re-runs the active route loaders, which is how the sidebar and navbar pick up the new logo without a full page reload.
Prevent UI flickering with the Derived State Pattern
After a successful upload, there is a brief moment between the mutation completing and the re-fetched query resolving. Without handling this, the UI can flash back to the old image. The Derived State Pattern eliminates this flicker by giving locally uploaded images priority over the cached value:currentImg to the <img> element and update uploadedImg inside onSuccess. The component displays the new image immediately — before the query re-fetch completes — because uploadedImg takes precedence in the derived expression.
Set up Supabase Storage
Configure environment variables
Add these two variables to your
.env file:VITE_SUPABASE_URL is safe to expose to the browser (it is the public project URL). SUPABASE_SERVICE_ROLE_KEY must never be sent to the client — keep it server-only.Use a custom bucket
TheuploadImage server function reads the bucket name from the FormData payload, defaulting to avatars. To upload to a different bucket, set the bucket field when building the FormData:
File size and type constraints
TheuploadImage function enforces a hard 2 MB limit server-side. You should also validate on the client before calling the server to provide faster feedback:

