Function Signature
deleteFile(
filename: string,
filelocation?: string
): Promise<void>
Description
Deletes a file from the specified directory in the configured file storage mount. The function validates the file path to prevent directory traversal attacks before deletion.
Parameters
The name of the file to delete. This should be the filename returned by storeFileLocally.
- Must be a safe basename (no path separators)
- Example:
"aBcD1234.png"
The folder path where the file is located, relative to the configured mount point.
- Use forward slashes for subdirectories (e.g.,
/userFiles or /uploads/images)
- Defaults to the root of the mount directory if not provided
- Path is automatically normalized and validated for security
Return Value
The function returns a Promise that resolves when the file is successfully deleted. It does not return any value.
Behavior Details
Path Validation
Before deletion, the function:
- Validates the filename is a safe basename
- Normalizes the file location path
- Ensures the target path is within the configured mount directory
- Prevents directory traversal attacks
If the file doesn’t exist, the function will throw an error. Consider wrapping the call in a try-catch block if you’re not certain the file exists.
Security
The function includes built-in security measures to prevent:
- Directory traversal attacks
- Deletion of files outside the mount directory
- Path manipulation attempts
Examples
Basic File Deletion
export default defineEventHandler(async (event) => {
const { filename } = await readBody(event)
await deleteFile(filename, '/userFiles')
return { success: true, message: 'File deleted successfully' }
})
Delete with Error Handling
export default defineEventHandler(async (event) => {
const { filename } = await readBody(event)
try {
await deleteFile(filename, '/uploads')
return { success: true }
} catch (error) {
console.error('File deletion failed:', error)
return { success: false, error: 'Failed to delete file' }
}
})
Delete Old File When Uploading New One
import type { ServerFile } from '#file-storage/types'
export default defineEventHandler(async (event) => {
const { file, oldFilename } = await readBody<{
file: ServerFile
oldFilename?: string
}>(event)
// Store the new file
const newFilename = await storeFileLocally(file, 8, '/avatars')
// Delete the old file if it exists
if (oldFilename) {
try {
await deleteFile(oldFilename, '/avatars')
} catch (error) {
console.warn('Could not delete old file:', oldFilename)
// Continue even if old file deletion fails
}
}
return { filename: newFilename }
})
User Profile Picture Update
export default defineEventHandler(async (event) => {
const userId = event.context.user?.id
if (!userId) {
throw createError({ statusCode: 401, message: 'Unauthorized' })
}
const { file } = await readBody<{ file: ServerFile }>(event)
// Get current avatar from database
const user = await db.users.findById(userId)
// Store new avatar
const newAvatar = await storeFileLocally(
file,
`user-${userId}-avatar`,
'/avatars'
)
// Delete old avatar if it exists
if (user.avatarFilename) {
await deleteFile(user.avatarFilename, '/avatars').catch(() => {})
}
// Update database
await db.users.update(userId, { avatarFilename: newAvatar })
return { avatarFilename: newAvatar }
})
Bulk File Deletion
export default defineEventHandler(async (event) => {
const { filenames } = await readBody<{ filenames: string[] }>(event)
const results = await Promise.allSettled(
filenames.map(filename => deleteFile(filename, '/uploads'))
)
const deleted = results.filter(r => r.status === 'fulfilled').length
const failed = results.filter(r => r.status === 'rejected').length
return {
deleted,
failed,
total: filenames.length
}
})
Cleanup Old Files
import { stat } from 'fs/promises'
export default defineEventHandler(async (event) => {
const files = await getFilesLocally('/temp')
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000)
let deletedCount = 0
for (const filename of files) {
try {
const filePath = getFileLocally(filename, '/temp')
const stats = await stat(filePath)
// Delete files older than 30 days
if (stats.mtime.getTime() < thirtyDaysAgo) {
await deleteFile(filename, '/temp')
deletedCount++
}
} catch (error) {
console.error(`Failed to process file ${filename}:`, error)
}
}
return { deletedCount }
})
Delete with Authorization
export default defineEventHandler(async (event) => {
const userId = event.context.user?.id
const { filename } = await readBody(event)
if (!userId) {
throw createError({ statusCode: 401, message: 'Unauthorized' })
}
// Verify the file belongs to the user
const file = await db.files.findOne({ filename, userId })
if (!file) {
throw createError({
statusCode: 403,
message: 'You do not have permission to delete this file'
})
}
// Delete the file
await deleteFile(filename, '/userFiles')
// Remove from database
await db.files.delete(file.id)
return { success: true }
})
Transaction-Safe Deletion
export default defineEventHandler(async (event) => {
const { fileId } = await readBody(event)
// Start database transaction
const transaction = await db.startTransaction()
try {
// Get file info from database
const file = await db.files.findById(fileId, { transaction })
if (!file) {
throw new Error('File not found in database')
}
// Delete from filesystem
await deleteFile(file.filename, file.location)
// Delete from database
await db.files.delete(fileId, { transaction })
// Commit transaction
await transaction.commit()
return { success: true }
} catch (error) {
// Rollback on error
await transaction.rollback()
throw createError({
statusCode: 500,
message: 'Failed to delete file'
})
}
})
Delete All User Files
export default defineEventHandler(async (event) => {
const { userId } = await readBody(event)
// Verify admin permissions
if (!event.context.user?.isAdmin) {
throw createError({ statusCode: 403, message: 'Forbidden' })
}
// Get all files for the user
const userFiles = await getFilesLocally(`/users/${userId}`)
// Delete each file
for (const filename of userFiles) {
try {
await deleteFile(filename, `/users/${userId}`)
} catch (error) {
console.error(`Failed to delete ${filename}:`, error)
}
}
return {
deletedCount: userFiles.length,
userId
}
})
Safe Delete with Backup
import { copyFile } from 'fs/promises'
export default defineEventHandler(async (event) => {
const { filename } = await readBody(event)
const filePath = getFileLocally(filename, '/uploads')
const backupPath = getFileLocally(filename, '/backups')
try {
// Create backup before deletion
await copyFile(filePath, backupPath)
// Delete original
await deleteFile(filename, '/uploads')
return {
success: true,
backed_up: true,
backup_location: '/backups'
}
} catch (error) {
throw createError({
statusCode: 500,
message: 'Failed to delete file'
})
}
})
Error Handling
The function throws an error if fileStorage.mount is not configured in your Nuxt config.
Common Errors
Mount not configured:
Error: fileStorage.mount is not configured
Solution: Add fileStorage.mount to your nuxt.config.ts
File not found:
Solution: Verify the file exists before attempting deletion
Permission denied:
Solution: Check file system permissions on the mount directory
Robust Error Handling
export default defineEventHandler(async (event) => {
const { filename } = await readBody(event)
try {
await deleteFile(filename, '/uploads')
return { success: true }
} catch (error: any) {
// Handle specific error codes
if (error.code === 'ENOENT') {
return {
success: false,
error: 'File not found'
}
}
if (error.code === 'EACCES') {
throw createError({
statusCode: 500,
message: 'Permission denied'
})
}
// Re-throw unexpected errors
throw error
}
})
Use Cases
- File replacement - Delete old files when users upload new ones
- Cleanup tasks - Remove temporary or expired files
- User actions - Allow users to delete their uploaded files
- Storage management - Free up space by removing unused files
- Account deletion - Remove all files when deleting user accounts
- Error recovery - Clean up partially uploaded files
- Cache invalidation - Remove cached or generated files
Important Notes
Deletion is permanent! There is no built-in recovery mechanism. Consider implementing:
- Soft deletes (mark as deleted in database)
- Backup mechanisms before deletion
- Trash/recycle bin functionality
- Confirmation prompts on the frontend
For production applications, consider:
- Logging all deletions for audit trails
- Implementing soft deletes for important files
- Adding deletion permissions/authorization
- Backing up files before deletion
- Using transaction-safe patterns when deleting from database and filesystem
See Also
Source
View the source code on GitHub.