nextjs-cms

Common Field Options

The options shared by every field type, explained with examples.

These options work on every field helper (textField, photoField, selectField, ...). Type-specific options are documented on each field's page.

OptionTypeDefault
namestringrequired
labelstring | Record<locale, string>generated from name
requiredbooleanfalse
defaultValuedepends on the fieldnone
ordernumbernone
conditionalRules[rule] | and(...) | or(...)none
adminGeneratedtrue | false | 'readonly'true
localizedbooleanfalse

name

The column name, and the key used in form submissions and hook values.

textField({ name: 'first_name' })
  • Must be unique within the section (case-insensitive), including across field groups.
  • id is reserved unless the field is the section's db.identifier. locale is reserved.
  • Renaming a field renames the column: update-sections detects the change and asks whether it's a rename (data kept) or a new field.

dateRangeField is the exception: it has startName and endName instead of name.

label

Text shown above the input. When omitted, it's generated from name: underscores become spaces, camelCase is split, and words are capitalized.

nameGenerated label
titleTitle
published_atPublished At
metaDescriptionMeta Description

Translate it for the admin UI with an object keyed by language code:

textField({
    name: 'title',
    label: { en: 'Title', ar: 'العنوان', fr: 'Titre' },
})

The admin shows the label for the editor's UI language, falling back to i18n.fallbackLanguage.

required

textField({ name: 'title', required: true })
  • The form refuses empty values, and the server checks again on submit.
  • The column is created NOT NULL, unless the field has conditionalRules (a hidden field has no value, so it must be nullable).
  • For file fields, "required" means a file must be uploaded on create; on edit, the existing file satisfies it.
  • checkboxField ignores required: unchecked is a valid value.

defaultValue

Pre-fills the form on the create page and becomes the column's SQL DEFAULT:

numberField({ name: 'stock', defaultValue: 0 })
checkboxField({ name: 'is_active', defaultValue: true })
selectField({ name: 'status', options: [/* ... */], defaultValue: 'draft' })
colorField({ name: 'accent', defaultValue: '#0070f3' })

The type depends on the field (a string for text fields, a number for numbers, and so on). Each field page lists what it accepts.

Combined with adminGenerated: false, a default value lets you store a value editors never see. See below.

order

Sorts fields inside the form (or inside their field group), lowest first. Fields without order come after all ordered fields, in array order.

fields: [
    textField({ name: 'subtitle', order: 2 }),
    textField({ name: 'notes' }), // no order: rendered last
    textField({ name: 'title', order: 1 }),
]
// Form: Title, Subtitle, Notes

In practice, leave order out everywhere and let the array order decide. Reach for it when fields are assembled from shared helpers. Field groups accept order too, with the same rule.

conditionalRules

Show a field only when other fields have certain values. A hidden field is not validated and not saved, so required means "required when visible".

import { and, or } from 'nextjs-cms/core/fields'

// One rule: pass a one-element array
conditionalRules: [{ field: type, condition: 'equals', value: 'external' }]

// Several rules: combine them explicitly
conditionalRules: and(
    { field: type, condition: 'equals', value: 'external' },
    { field: price, condition: 'greaterThan', value: 0 },
)
conditionalRules: or(
    { field: status, condition: 'equals', value: 'scheduled' },
    { field: status, condition: 'equals', value: 'published' },
)

Conditions: equals, notEquals, contains, notContains, greaterThan, lessThan, greaterThanOrEquals, lessThanOrEquals.

The full guide, with semantics and patterns, is Conditional Fields.

adminGenerated

Controls whether editors fill in the field:

ValueCreate/edit formSaved from the form
true (default)Editable inputYes
'readonly'Shown as read-only textNo
falseHiddenNo (the column's default applies)

'readonly': show a value that something else maintains

// A counter your website updates; editors can see it but not change it.
numberField({ name: 'view_count', label: 'Views', adminGenerated: 'readonly' })

false: a column editors never see

// Filled by your website or an import job, invisible in the admin.
textField({ name: 'external_ref', adminGenerated: false })

// Stored on create with a fixed value, editors never see it.
textField({ name: 'source', adminGenerated: false, defaultValue: 'cms' })

For textField and slugField, a field with adminGenerated: false and a defaultValue is still written with that default on create.

Good to know:

Auto-increment number fields are always adminGenerated: false. The database assigns the value.

localized

Mark a field as translatable. Requires localization in cms.config.ts.

textField({ name: 'title', required: true, localized: true })
richTextField({ name: 'body', localized: true })
photoField({ name: 'banner', localized: true }) // a different banner per language
  • The default locale's value is stored in the section's table; other locales in {table}_locales.
  • Non-localized fields are shared: editing them in any locale changes them everywhere.
  • The section identifier can't be localized.

Read the Localization guide for the storage model and how to query translations.