---
title: "Upload Field"
aliases: [upload-field, payload-upload, media-field]
tags: [payloadcms, fields, upload, media, relationships]
sources: [raw/fields__upload.md]
created: 2026-05-15
updated: 2026-05-15
---

The Upload Field references a document from an upload-enabled Collection, rendered as a thumbnail in the Admin Panel. It is a typed relationship to a media/file Collection.

## Basic Config

```ts
import type { Field } from 'payload'

export const MyUploadField: Field = {
  type: 'upload',
  name: 'backgroundImage',   // required
  relationTo: 'media',       // required — must be an upload-enabled collection
  required: true,
}
```

> **Prerequisite:** target Collection must have `upload: true` (or an upload config object) in its [[wiki/payloadcms/collection-config|Collection Config]].

## Key Config Options

| Option | Description |
|--------|-------------|
| `relationTo` | Single slug or array of slugs (polymorphic). **Must** point to upload collection(s). |
| `hasMany` | `true` → accepts multiple uploads |
| `minRows` / `maxRows` | Validation bounds when `hasMany: true` |
| `filterOptions` | `Where` query or function — limits selectable files in UI and validates on save |
| `displayPreview` | Override Collection-level preview thumbnail setting |
| `maxDepth` | Max auto-populate depth for related document |
| `unique` | DB-level unique index |
| `localized` | Per-locale upload reference |
| `virtual` | Skip DB storage or link to a relationship path |
| `saveToJWT` | Include in JWT if field is top-level in an auth Collection |

## Filtering Upload Options

Restrict selectable files dynamically:

```ts
// Static Where query — only images
const imageField = {
  name: 'image',
  type: 'upload',
  relationTo: 'media',
  filterOptions: {
    mimeType: { contains: 'image' },
  },
}
```

As a function (receives `{ relationTo, data, siblingData, id, user, req }`):

```ts
filterOptions: ({ user }) => {
  if (user.role === 'admin') return true   // no filter
  return { uploadedBy: { equals: user.id } }
}
```

> **Gotcha:** If you combine `filterOptions` with a custom `validate` function, call the default upload field validator from `payload/shared` inside your function — otherwise `filterOptions` won't be validated by the API.

## Polymorphic Uploads

Reference multiple upload collections:

```ts
{
  name: 'media',
  type: 'upload',
  relationTo: ['images', 'documents', 'videos'],
  hasMany: true,   // optional — allow multiple selections
}
```

When polymorphic, the stored value is `{ relationTo: 'images', value: '<id>' }` (same shape as polymorphic [[wiki/payloadcms/fields-relationship|Relationship Field]]).

## Bi-directional Relationships

The upload field alone is a one-way reference. To view from the media document which other documents use it, add a [[wiki/payloadcms/fields-join|Join Field]] on the upload Collection pointing back.

## Key Takeaways

- `relationTo` is **required** and must point to an upload-enabled Collection — a plain Collection won't work
- Use `hasMany: true` for galleries / multi-file selectors; pair with `minRows`/`maxRows` for validation
- `filterOptions` filters both UI picker and API validation — mix with `where` queries from [[wiki/payloadcms/queries|Queries]]
- Combining `filterOptions` + custom `validate` requires calling the built-in validator from `payload/shared`
- Polymorphic: pass an array to `relationTo` — stored value gets a `{ relationTo, value }` wrapper
- For reverse lookup (where is this media used?), use [[wiki/payloadcms/fields-join|Join Field]] on the media Collection
- `displayPreview` can be overridden per-field, independent of the Collection setting

## Sources

- `raw/fields__upload.md` — Payload CMS official docs, Upload Field
