If you don't specify an "id" field there will be an automatically generated id for each entry in a media collection, is it possible to default to the filename or does it require me to use hooks to achieve this?
You can use the filename as the ID with a beforeOperation hook, but there are some considerations:
const Media = {
slug: 'media',
upload: {
staticDir: 'media',
},
hooks: {
beforeOperation: [
async ({ args, operation }) => {
if (operation === 'create' && args.req?.file) {
// Use filename as ID (sanitized)
const filename = args.req.file.name
const nameWithoutExt = filename.replace(/\.[^/.]+$/, '')
args.data.id = nameWithoutExt.toLowerCase().replace(/[^a-z0-9-]/g, '-')
}
return args
}
]
},
// ... rest of config
}Important:
This will fail if you upload files with duplicate names
Consider using a beforeChange hook instead to add the filename as a separate indexed field while keeping auto-generated IDs
Or add a timestamp: args.data.id = \sanitizedName−{sanitizedName}-
sanitizedName−{Date.now()}``
The auto-generated ID is usually better for uniqueness.
hmm that makes sense, the reason i wanted to do this is because i want one of each file to be created, if a file with the same name is uploaded it should be overwritten instead
For overwriting duplicate files, here's a different approach using beforeValidate:
hooks: {
beforeValidate: [
async ({ data, req, operation }) => {
if (operation === 'create' && data.filename) {
const nameWithoutExt = data.filename.replace(/\.[^/.]+$/, '')
const sanitizedId = nameWithoutExt.toLowerCase().replace(/[^a-z0-9-]/g, '-')
// Set the custom ID
data.id = sanitizedId
// Check if this ID already exists
try {
await req.payload.findByID({
collection: 'media',
id: sanitizedId,
})
// If we get here, file exists - convert to update
req.context.overwriteExisting = sanitizedId
} catch (e) {
// File doesn't exist, proceed with create
}
}
return data
}
],
beforeChange: [
async ({ context, req, operation }) => {
if (context?.overwriteExisting && operation === 'create') {
// Delete the existing file
await req.payload.delete({
collection: 'media',
id: context.overwriteExisting,
})
}
}
]
}This splits the logic: beforeValidate sets the ID and detects duplicates, beforeChange handles the deletion. The file gets replaced with the same ID, achieving the overwrite behavior you want.
Star
Discord
online
Get dedicated engineering support directly from the Payload team.