Documentation Index
Fetch the complete documentation index at: https://mintlify.com/remix-run/remix/llms.txt
Use this file to discover all available pages before exploring further.
Form Data Middleware
Form body parsing middleware that parses incoming FormData and exposes it via context.get(FormData).
Installation
Function
Creates middleware that parses FormData from the request body and populates request context.
Signature:
function formData(options?: FormDataOptions): Middleware
Parameters:
options - Optional form data parsing settings
Returns: A middleware function that parses form data.
Options
interface FormDataOptions extends ParseFormDataOptions {
suppressErrors?: boolean
uploadHandler?: FileUploadHandler
}
suppressErrors
Set true to suppress parse errors. When enabled, invalid form data will result in an empty FormData object instead of throwing an error.
- Type:
boolean
- Default:
false
uploadHandler
A function that handles file uploads. It receives a FileUpload object and may return any value that is a valid FormData value. Default is undefined, which means file uploads are stored in memory.
- Type:
FileUploadHandler
- Default:
undefined
Signature:
type FileUploadHandler = (upload: FileUpload) => Promise<File | string | null>
Basic Usage
import { createRouter } from 'remix/fetch-router'
import { formData } from 'remix/form-data-middleware'
let router = createRouter({
middleware: [formData()],
})
router.post('/users', async (context) => {
let formData = context.get(FormData)
let name = formData.get('name')
let email = formData.get('email')
return Response.json({ name, email })
})
File Uploads
Uploaded files are available in the parsed FormData object. For a single file field, use formData.get(name). For repeated file fields, use formData.getAll(name).
import { createRouter } from 'remix/fetch-router'
import { formData } from 'remix/form-data-middleware'
let router = createRouter({
middleware: [formData()],
})
router.post('/upload', async (context) => {
let formData = context.get(FormData)
let avatar = formData.get('avatar')
if (avatar instanceof File) {
console.log('Uploaded file:', avatar.name, avatar.size, 'bytes')
}
return Response.json({ hasAvatar: avatar instanceof File })
})
Custom Upload Handler
You can use a custom upload handler to customize how file uploads are handled. The return value of the upload handler will be used as the value of the form field in the FormData object.
import { formData } from 'remix/form-data-middleware'
import { writeFile } from 'node:fs/promises'
let router = createRouter({
middleware: [
formData({
async uploadHandler(upload) {
// Save to disk and return path
let path = `./uploads/${upload.name}`
await writeFile(path, Buffer.from(await upload.arrayBuffer()))
return path
},
}),
],
})
router.post('/upload', async (context) => {
let formData = context.get(FormData)
let avatarPath = formData.get('avatar') // Returns the file path string
return Response.json({ avatarPath })
})
Suppress Errors
Some requests may contain invalid form data that cannot be parsed. You can suppress parse errors by setting suppressErrors to true.
let router = createRouter({
middleware: [
formData({
suppressErrors: true, // Invalid form data won't throw
}),
],
})
Multiple File Upload
import { createRouter } from 'remix/fetch-router'
import { formData } from 'remix/form-data-middleware'
let router = createRouter({
middleware: [formData()],
})
router.post('/upload-multiple', async (context) => {
let formData = context.get(FormData)
let images = formData.getAll('images') // Get all files with name="images"
let files = images.filter((item): item is File => item instanceof File)
return Response.json({
count: files.length,
sizes: files.map(f => f.size),
})
})
Types
FileUpload
interface FileUpload {
name: string
type: string
arrayBuffer(): Promise<ArrayBuffer>
}
Thrown when form data parsing fails (unless suppressErrors is true).
import { FormDataParseError } from 'remix/form-data-middleware'
try {
// Parse form data
} catch (error) {
if (error instanceof FormDataParseError) {
console.error('Form data parsing failed:', error.message)
}
}