How to Handle File Upload in Remix: Fix and Best Practices
FormData API on the client and parsing the multipart form data in the action function with unstable_parseMultipartFormData. This ensures files are correctly received and processed on the server side.Why This Happens
Developers often try to handle file uploads in Remix by reading request.formData() directly without parsing multipart data properly. This causes the file data to be missing or unusable because Remix needs explicit parsing for multipart forms.
export const action = async ({ request }) => { const formData = await request.formData(); const file = formData.get('file'); // file is a File object but may not be handled correctly console.log(file); return null; };
The Fix
Use Remix's unstable_parseMultipartFormData utility with a file upload handler to properly parse the multipart form data. This lets you access the uploaded file's stream or buffer safely in the action function.
import { unstable_parseMultipartFormData, uploadHandler } from '@remix-run/node'; export const action = async ({ request }) => { const handler = uploadHandler({ maxFileSize: 5_000_000, // 5MB limit }); const formData = await unstable_parseMultipartFormData(request, handler); const file = formData.get('file'); if (!file) { return { error: 'No file uploaded' }; } // file is a File object with stream access console.log('File name:', file.name); return { success: true }; };
Prevention
Always use unstable_parseMultipartFormData with an upload handler for file uploads in Remix. Validate file size and type to avoid server overload or security risks. Use client-side form encType="multipart/form-data" and test uploads with real files.
Enable linting rules to catch missing multipart parsing and keep dependencies updated to use the latest Remix APIs.
Related Errors
Common related errors include:
- Empty file data: caused by missing
encType="multipart/form-data"on the form. - File size too large: fix by setting
maxFileSizein the upload handler. - Incorrect file field name: ensure the form input name matches the key used in
formData.get().