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.
Key/value storage interfaces for server-side File objects. file-storage gives Remix apps one consistent API across local disk and memory backends.
Features
- Simple API - Intuitive key/value API (like Web Storage, but for
Files instead of strings)
- Multiple Backends - Built-in filesystem and memory backends
- Streaming Support - Stream file content to and from storage
- Metadata Preservation - Preserves all
File metadata including file.name, file.type, and file.lastModified
Installation
Usage
File System Storage
import { createFsFileStorage } from 'remix/file-storage/fs'
let storage = createFsFileStorage('./user/files')
let file = new File(['hello world'], 'hello.txt', { type: 'text/plain' })
let key = 'hello-key'
// Put the file in storage.
await storage.set(key, file)
// Then, sometime later...
let fileFromStorage = await storage.get(key)
// All of the original file's metadata is intact
fileFromStorage.name // 'hello.txt'
fileFromStorage.type // 'text/plain'
// To remove from storage
await storage.remove(key)
Memory Storage
Memory storage is useful for testing and development:
import { createMemoryFileStorage } from 'remix/file-storage/memory'
let storage = createMemoryFileStorage()
let file = new File(['test data'], 'test.txt', { type: 'text/plain' })
await storage.set('test-key', file)
let retrieved = await storage.get('test-key')
console.log(await retrieved.text()) // 'test data'
Working with File Uploads
file-storage pairs well with form-data-parser for handling file uploads:
import { createFsFileStorage } from 'remix/file-storage/fs'
import { parseFormData } from 'remix/form-data-parser'
let storage = createFsFileStorage('./uploads')
async function handleUpload(request: Request) {
let formData = await parseFormData(request)
let file = formData.get('avatar')
if (file instanceof File) {
// Generate a unique key for the file
let key = `${Date.now()}-${file.name}`
// Store the file
await storage.set(key, file)
return Response.json({
success: true,
key,
filename: file.name,
size: file.size,
type: file.type,
})
}
return Response.json({ error: 'No file uploaded' }, { status: 400 })
}
Serving Files from Storage
Use with response helpers to serve files with proper HTTP semantics:
import { createFsFileStorage } from 'remix/file-storage/fs'
import { createFileResponse } from 'remix/response/file'
let storage = createFsFileStorage('./uploads')
async function handleDownload(request: Request, key: string) {
let file = await storage.get(key)
if (!file) {
return new Response('File not found', { status: 404 })
}
return createFileResponse(file, request, {
cacheControl: 'public, max-age=3600',
})
}
Streaming Large Files
File storage works efficiently with large files using streams:
import { createFsFileStorage } from 'remix/file-storage/fs'
let storage = createFsFileStorage('./large-files')
// Store a large file (uses streaming internally)
let largeFile = new File([await readFileData()], 'video.mp4', {
type: 'video/mp4',
})
await storage.set('video-key', largeFile)
// Retrieve and stream to response
let file = await storage.get('video-key')
return new Response(file.stream(), {
headers: {
'Content-Type': file.type,
'Content-Disposition': `attachment; filename="${file.name}"`,
},
})
API Reference
createFsFileStorage(directory)
Creates a file storage instance that stores files on the filesystem.
Parameters:
directory: string - Path to the directory where files will be stored
Returns: FileStorage
createMemoryFileStorage()
Creates a file storage instance that stores files in memory.
Returns: FileStorage
FileStorage
Interface for file storage implementations.
interface FileStorage {
/** Store a file with the given key */
set(key: string, file: File): Promise<void>
/** Retrieve a file by key */
get(key: string): Promise<File | null>
/** Check if a file exists */
has(key: string): Promise<boolean>
/** Remove a file by key */
remove(key: string): Promise<void>
/** List all file keys (optional pagination) */
list(options?: ListOptions): Promise<ListResult>
}
interface ListOptions {
/** Maximum number of keys to return */
limit?: number
/** Pagination cursor from previous list() call */
cursor?: string
}
interface ListResult {
/** Array of file keys */
keys: string[]
/** Cursor for next page (if more results available) */
cursor?: string
}
All standard File properties are preserved:
name: string - The filename
size: number - File size in bytes
type: string - MIME type
lastModified: number - Last modified timestamp
External Storage Backends
For cloud storage, use external backends:
form-data-parser - Parse multipart/form-data requests with file uploads
lazy-file - The streaming File implementation used internally
response/file - Create file responses with proper HTTP semantics