How the Module Works
nuxt-file-storage provides a complete solution for file handling in Nuxt applications by bridging the gap between frontend file inputs and backend storage. The module consists of two main parts that work together:
Frontend Composable (useFileStorage) - Handles file input processing and serialization
Backend Server Utilities - Manages secure file storage and retrieval
The module leverages Nuxt’s module system and Nitro’s server engine to provide seamless integration between client and server.
File Flow Architecture
The complete journey of a file through the system follows this flow:
When a user selects files through an <input type="file"> element, the browser provides a FileList object containing native File objects.
2. Serialization
The useFileStorage composable processes each file:
// From useFileStorage.ts:10-28
const serializeFile = ( file : ClientFile ) : Promise < void > => {
return new Promise < void >(( resolve , reject ) => {
const reader = new FileReader ()
reader . onload = ( e : ProgressEvent < FileReader >) => {
files . value . push ({
... file ,
name: file . name ,
size: file . size ,
type: file . type ,
lastModified: file . lastModified ,
content: e . target ?. result , // Base64 data URL
})
resolve ()
}
reader . onerror = ( error ) => reject ( error )
reader . readAsDataURL ( file )
})
}
The FileReader API converts binary file data into a base64-encoded data URL format that can be safely transmitted over HTTP.
3. Transfer
The serialized files are sent to the backend as part of a request body:
const response = await $fetch ( '/api/files' , {
method: 'POST' ,
body: { files: files . value }
})
4. Backend Storage
On the server, files arrive as ServerFile objects and are processed by utility functions:
import type { ServerFile } from 'nuxt-file-storage'
export default defineEventHandler ( async ( event ) => {
const { files } = await readBody <{ files : ServerFile [] }>( event )
for ( const file of files ) {
await storeFileLocally (
file , // ServerFile object
8 , // ID length or custom filename
'/uploads' // Storage directory
)
}
} )
The Role of Each API Component
Frontend Composable: useFileStorage
Purpose: Simplify file input handling and prepare files for network transfer
Key responsibilities:
Process FileList objects from file inputs
Serialize files to data URLs using FileReader API
Manage file state in a reactive Vue ref
Handle multiple file selections
Optionally clear previous selections
When to use:
Any component with file input elements
When you need reactive file state
When preparing files for API requests
Example:
< script setup >
const { handleFileInput , files , clearFiles } = useFileStorage ({
clearOldFiles: true // Clear on new selection
})
</ script >
Backend Storage Utilities
Purpose: Securely receive, validate, and store files on the server filesystem
Key functions:
storeFileLocally
Stores a file with automatic ID generation or custom naming
// Auto-generated filename with 8 character ID
await storeFileLocally ( file , 8 , '/userFiles' )
// Returns: "a7Kj9mP2.jpg"
// Custom filename
await storeFileLocally ( file , 'profile-photo' , '/avatars' )
// Returns: "profile-photo.jpg"
getFileLocally
Returns the absolute path to a stored file
const filePath = getFileLocally ( 'a7Kj9mP2.jpg' , '/userFiles' )
// Returns: "/home/user/storage/userFiles/a7Kj9mP2.jpg"
retrieveFileLocally
Streams a file to the client with proper headers
return await retrieveFileLocally ( event , 'document.pdf' , '/documents' )
// Sets Content-Type, Content-Length, and streams the file
deleteFile
Removes a file from storage
await deleteFile ( 'old-file.jpg' , '/temp' )
getFilesLocally
Lists all files in a directory
const files = await getFilesLocally ( '/userFiles' )
// Returns: ['file1.jpg', 'file2.pdf', 'file3.png']
When to use:
In API route handlers that receive files
When you need to manage stored files
When serving files to clients
When implementing file galleries or listings
Configuration Requirements
Before using the backend utilities, you must configure the storage mount point:
// nuxt.config.ts
export default defineNuxtConfig ({
modules: [ 'nuxt-file-storage' ] ,
fileStorage: {
mount: '/absolute/path/to/storage'
}
})
The mount path must be an absolute path. All file operations are contained within this directory for security.
Using environment variables (recommended):
// nuxt.config.ts
export default defineNuxtConfig ({
fileStorage: {
mount: process . env . FILE_STORAGE_MOUNT
}
})
# .env
FILE_STORAGE_MOUNT = /home/user/project/storage
When to Use Each Part of the API
Use Frontend Composable When:
Building upload forms
Creating file pickers
Implementing drag-and-drop file zones
Previewing files before upload
Managing multiple file input fields
Use Backend Storage When:
Receiving uploaded files in API routes
Persisting files to the filesystem
Implementing file download endpoints
Managing file lifecycle (store, retrieve, delete)
Building file management systems
Use Both Together For:
Complete upload flow:
<!-- Frontend -->
< template >
< input type = "file" @ input = " handleFileInput " multiple />
< button @ click = " uploadFiles " > Upload </ button >
</ template >
< script setup >
const { handleFileInput , files } = useFileStorage ()
const uploadFiles = async () => {
await $fetch ( '/api/upload' , {
method: 'POST' ,
body: { files: files . value }
})
}
</ script >
// Backend - server/api/upload.ts
import type { ServerFile } from 'nuxt-file-storage'
export default defineEventHandler ( async ( event ) => {
const { files } = await readBody <{ files : ServerFile [] }>( event )
const storedFiles = []
for ( const file of files ) {
const filename = await storeFileLocally ( file , 8 , '/uploads' )
storedFiles . push ( filename )
}
return { success: true , files: storedFiles }
} )
For production applications, consider adding validation, file type checking, size limits, and user authentication to your file upload endpoints.
Type Safety
The module provides TypeScript types for both client and server:
// Frontend
import type { ClientFile } from 'nuxt-file-storage'
// Backend
import type { ServerFile } from 'nuxt-file-storage'
// Module configuration
import type { ModuleOptions } from 'nuxt-file-storage'
ClientFile interface:
interface ClientFile extends Blob {
content : string | ArrayBuffer | null | undefined
name : string
lastModified : number
}
ServerFile interface:
interface ServerFile {
name : string
content : string // Base64 data URL
size : string
type : string
lastModified : string
}
Next Steps
Frontend Handling Deep dive into useFileStorage and client-side file processing
Backend Storage Learn about server-side storage strategies and utilities
Security Understand built-in security features and best practices
API Reference Complete API documentation and examples