File Upload Reference
Use useFileUpload to upload user-selected files to blob storage and receive a public URL that can be displayed, persisted, passed to AI hooks, or downloaded later.
useFileUpload
Returns
uploadFile(function): Upload aFileand resolve to the result shape below orundefined.isLoading(boolean): Whether an upload is in progress.error(Error | null): Current upload error.file(object | null): Last uploaded file result.
Result Shape
name(string): Original file name.contentType(string): MIME type.url(string): Public URL to the uploaded file.
Supported File Types
Common supported MIME types include:
- Images:
image/png,image/jpeg,image/webp,image/heic, andimage/heif. - Audio:
audio/mpeg,audio/mp3,audio/wav,audio/aiff,audio/x-aiff,audio/aac,audio/ogg, andaudio/flac. - Video:
video/mp4,video/mpeg,video/mov,video/avi,video/x-flv,video/mpg,video/webm,video/wmv, andvideo/3gpp. - Documents:
application/pdf.
Example
Import the hook from the file upload module:
import { useFileUpload } from '@/hooks/use-file-upload'
import { usePersistentItem } from '@/hooks/use-persistent-item'
export default function App() {
const [uploadedImageUrl, setUploadedImageUrl] = usePersistentItem<
string | null
>('uploadedImageUrl', null)
const [selectedFile, setSelectedFile] = React.useState<File | null>(null)
const { uploadFile, isLoading, error } = useFileUpload()
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSelectedFile(event.target.files?.[0] ?? null)
}
const handleUpload = async () => {
if (!selectedFile) return
const result = await uploadFile(selectedFile)
if (result) {
setUploadedImageUrl(result.url)
setSelectedFile(null)
}
}
return (
<div>
<div className="flex gap-2">
<input
type="file"
accept="image/png, image/jpeg, image/webp"
onChange={handleFileChange}
/>
<button onClick={handleUpload} disabled={!selectedFile || isLoading}>
{isLoading ? (
<span className="mr-2 inline-block animate-spin rounded-full border-2 border-current border-t-transparent" />
) : null}
Upload
</button>
</div>
{error ? <p className="text-destructive">{error.message}</p> : null}
{uploadedImageUrl ? (
<img
src={uploadedImageUrl}
alt="Uploaded"
className="w-full rounded-lg"
/>
) : null}
</div>
)
}
Error Handling
Uploads return undefined on failure:
const { uploadFile, error } = useFileUpload()
const handleUpload = async (file: File) => {
const result = await uploadFile(file)
if (!result) {
return
}
console.log('Uploaded to:', result.url)
}
Render error from the hook in component JSX. React state updates on the next render, so the value in the same event-handler closure may still be from the previous render immediately after await uploadFile(...).
Best Practices
- Upload one file at a time per hook instance. Use multiple hook instances for concurrent uploads.
- Persist
result.urlwithusePersistentItemwhen the file should survive reloads. - Stream files directly to storage instead of reading large files into memory.
- Use the returned
contentTypewhen displaying or categorizing uploaded files. - Pass uploaded URLs to AI hooks as
{ url }attachments when you need AI processing. - Keep local
Filestate separate from persisted URLs so users can clear or retry selections cleanly.