11 KiB
PayloadCMS — Fields: Basic
Overview
Scalar (basic) fields store a single value per document. They map directly to database columns and drive typed inputs in the Admin Panel. All fields live inside the fields array of a wiki/payloadcms/configuration (Collection or Global).
See wiki/payloadcms/fields-complex for structural/relational fields.
Field Types Quick Reference
| Field | Type string | Key options |
|---|---|---|
| Text | text |
minLength, maxLength, hasMany, unique |
| Textarea | textarea |
minLength, maxLength, admin.rows |
| Number | number |
min, max, hasMany, admin.step |
email |
unique, index |
|
| Date | date |
timezone, admin.date.pickerAppearance |
| Checkbox | checkbox |
defaultValue (boolean) |
| Code | code |
admin.language, admin.editorOptions |
| JSON | json |
jsonSchema (local or remote) |
| Point | point |
index defaults to 2dsphere, not supported in SQLite |
| Radio | radio |
options (required), admin.layout |
| Select | select |
options, hasMany, filterOptions, enumName |
| UI | ui |
admin.components.Field (required), presentational only |
Common Field Options
These options are shared by almost all data-storing fields:
| Option | Type | Description |
|---|---|---|
name * |
string |
Property name in DB and API. Required for data fields. |
label |
string | Record<string,string> |
Admin Panel label, auto-generated from name if omitted. |
required |
boolean |
Prevents saving without a value. |
defaultValue |
any | Initial value; can be a static value or async function. |
unique |
boolean |
DB-level unique index across the collection. |
index |
boolean |
Creates a DB index for faster queries. |
localized |
boolean |
Stores a per-locale copy. Requires localization enabled globally. |
hidden |
boolean |
Hides from all APIs and Admin; still saved to DB. |
validate |
function |
Custom validation, runs on both client and server. |
hooks |
object |
beforeValidate, beforeChange, afterChange, afterRead. |
access |
object |
Field-level read/create/update access control functions. |
saveToJWT |
boolean |
Include value in user JWT (auth collections only, top-level fields). |
virtual |
boolean | string |
true = not persisted to DB; string path = virtual relationship link. |
custom |
object |
Arbitrary extension data for plugins. |
typescriptSchema |
JSONSchema |
Override generated TypeScript type with a JSON schema. |
Admin-level sub-options available on all fields (via admin: {}):
| Option | Description |
|---|---|
description |
Help text rendered below the field. |
condition |
(data, siblingData) => boolean — conditional rendering. |
readOnly |
Renders as read-only in Admin. |
disabled |
Disables the field UI (granular: { field?, column?, filter?, ... }). |
position |
'sidebar' to move field to the document sidebar. |
width |
CSS width for use inside row fields (e.g. '50%'). |
components |
Override Field, Label, Cell React components. |
Each Field
Text
Stores a string. Most commonly used field.
import type { Field } from 'payload'
const titleField: Field = {
name: 'pageTitle',
type: 'text',
required: true,
minLength: 3,
maxLength: 120,
admin: {
placeholder: 'Enter page title...',
autoComplete: 'off',
rtl: false,
},
}
Extra options: minLength, maxLength, hasMany (array of strings), minRows, maxRows (when hasMany), admin.placeholder, admin.autoComplete, admin.rtl.
Slug Field shortcut: import { slugField } from 'payload' — auto-generates URL slug from another field with a lock/unlock UI.
Gotcha: unique: true creates a collection-wide DB index, not per-document uniqueness.
Textarea
Nearly identical to Text but renders a taller input — use for descriptions, bios, meta.
const descField: Field = {
name: 'metaDescription',
type: 'textarea',
maxLength: 160,
admin: {
rows: 3,
placeholder: 'Short summary...',
},
}
Extra options: same as Text plus admin.rows (default 2).
Number
Stores a numeric value.
const priceField: Field = {
name: 'price',
type: 'number',
min: 0,
required: true,
admin: {
step: 0.01,
placeholder: '0.00',
},
}
Extra options: min, max, hasMany, minRows, maxRows, admin.step, admin.placeholder, admin.autoComplete.
Like Text but validates that the value is a valid email address.
const emailField: Field = {
name: 'contactEmail',
type: 'email',
required: true,
unique: true,
admin: {
placeholder: 'user@example.com',
},
}
No unique-to-email options beyond standard text options. Format validation is automatic.
Date
Stores a full ISO datetime string (YYYY-MM-DDTHH:mm:ss.SSSZ). UI uses react-datepicker.
const publishedAtField: Field = {
name: 'publishedAt',
type: 'date',
required: true,
admin: {
date: {
pickerAppearance: 'dayAndTime', // dayAndTime | dayOnly | timeOnly | monthOnly
displayFormat: 'd MMM yyyy HH:mm',
timeIntervals: 15,
},
},
}
Timezone support:
{
name: 'eventTime',
type: 'date',
timezone: {
defaultTimezone: 'America/New_York',
supportedTimezones: [
{ label: 'New York', value: 'America/New_York' },
{ label: 'London', value: 'Europe/London' },
],
},
}
Timezone value is saved in a companion column <fieldName>_tz. Date is always stored in UTC — handle conversion in your frontend.
displayFormat only affects the cell display; the stored value is always full ISO.
Checkbox
Stores a boolean.
const featuredField: Field = {
name: 'isFeatured',
type: 'checkbox',
defaultValue: false,
}
Gotcha: When required: true, defaultValue must be true — otherwise required validation will always fail on false.
Code
Stores a string but renders a Monaco-editor code block in Admin.
const snippetField: Field = {
name: 'trackingCode',
type: 'code',
admin: {
language: 'javascript', // any Monaco language slug
editorOptions: { lineNumbers: 'off' },
},
}
Gotcha: Saves as raw string to DB — not parsed. Different from JSON field.
JSON
Stores raw JSON (parsed object/array) in the DB. Also Monaco-editor UI.
const configField: Field = {
name: 'settings',
type: 'json',
jsonSchema: {
uri: 'a://schema/settings.json', // required — must be unique URI
fileMatch: ['a://schema/settings.json'], // required
schema: {
type: 'object',
properties: {
theme: { enum: ['light', 'dark'] },
},
},
},
}
jsonSchema enables typeahead in Admin and validates on save. Can also point to a remote URL — Payload fetches the schema.
Gotcha: Code field stores string; JSON field stores a parsed value — do not confuse them.
Point
Stores GeoJSON [longitude, latitude] coordinates with an automatic 2dsphere index.
const locationField: Field = {
name: 'location',
type: 'point',
}
Supports geospatial query operators: near, within (polygon), intersects (polygon).
Gotcha: Not supported in SQLite. Disabling the index (index: false) removes geospatial query support.
Radio
Single-select from a predefined list. Renders a radio group.
const statusField: Field = {
name: 'status',
type: 'radio',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
{ label: 'Archived', value: 'archived' },
],
defaultValue: 'draft',
admin: {
layout: 'horizontal', // horizontal | vertical
},
}
Gotcha: Option value strings must not contain hyphens — GraphQL enum constraint. Underscores are fine.
Select
Dropdown single or multi-select from a predefined list.
const tagsField: Field = {
name: 'tags',
type: 'select',
hasMany: true,
options: [
{ label: 'News', value: 'news' },
{ label: 'Tutorial', value: 'tutorial' },
{ label: 'Release', value: 'release' },
],
admin: {
isClearable: true,
isSortable: true, // drag-and-drop reorder, only when hasMany
},
}
filterOptions — function receiving { options, data, siblingData, ... } that returns a filtered options array (different from relationship filterOptions which returns a Where query).
Extra options: enumName (custom Postgres enum name), dbName (custom join table name when hasMany), interfaceName.
UI
Presentational-only. No data stored. Renders a custom React component anywhere in the field schema.
const helpTextField: Field = {
name: 'myHelper',
type: 'ui',
admin: {
components: {
Field: '/path/to/MyHelpText', // required
Cell: '/path/to/MyHelpCell', // optional — list view column
},
},
}
Use cases: custom buttons (Refund, Clear Cache, View Page), contextual help text, action components.
Gotcha: admin.components.Field is required — without it nothing renders. Does not participate in validation or hooks.
Gotchas
unique: trueon nested fields (inside Array/Group) creates a collection-wide index, not per-row uniqueness. Use a customvalidatefor per-row enforcement.hidden: truestill persists data to DB — use fieldaccessto truly restrict reads.localized: truerequires global localization config (i18n) to be enabled first.virtual: trueprevents DB storage entirely; useful for computed/derived fields.- Radio/Select values must not contain hyphens — GraphQL enum naming constraint.
- Point field is unsupported in SQLite databases.
- Date timezone column is auto-named
<fieldName>_tz; date itself stored in UTC.