nextjs-cms

numberField

Integers and decimals with range checks. The column type is chosen from the range you declare.

import { numberField } from 'nextjs-cms/core/fields'

Basic usage

numberField({ name: 'quantity' })

An integer input stored in an INT(11) column.

With every option

numberField({
    name: 'price',
    label: { en: 'Price (USD)', ar: 'السعر' },
    required: true,
    order: 3,
    localized: false,
    adminGenerated: true,
    conditionalRules: [{ field: isPaid, condition: 'equals', value: true }],

    format: 'float',
    placeholder: '0.00',
    minValue: 0,
    maxValue: 99_999.99,
    minLength: 1,
    maxLength: 8,
    defaultValue: 0,
    rtl: false,
})

Options

OptionTypeDefaultDescription
format'int' | 'float' | 'double' | 'bigint''int'Number kind, and the column type family.
minValuenumbernoneSmallest allowed value. minValue >= 0 also makes the column UNSIGNED.
maxValuenumbernoneLargest allowed value.
minLengthnumbernoneMinimum number of digits (length of the value as a string).
maxLengthnumbernoneMaximum number of digits. For integers, also the column display width.
placeholderstringnoneHint in the empty input.
defaultValuenumbernonePre-filled value and column default.
rtlbooleanlocale-basedForce the input direction.
hasAutoIncrementtruefalseAuto-increment mode. See below.

Plus the common options. The field throws on load if minValue > maxValue or minLength > maxLength.

Options in detail

format

formatAcceptsColumn
'int' (default)Whole numbersSmallest integer type that fits the range (see below)
'bigint'Whole numbers beyond ±2.1 billionBIGINT
'float'Decimals, ~7 significant digitsFLOAT
'double'Decimals, ~15 significant digitsDOUBLE
numberField({ name: 'rating', format: 'double', minValue: 0, maxValue: 5 })
numberField({ name: 'population', format: 'bigint', minValue: 0 }) // BIGINT UNSIGNED
Warning:

FLOAT and DOUBLE are binary floating-point: 0.1 + 0.2 isn't exactly 0.3. For money, store integer cents (numberField({ name: 'price_cents', minValue: 0, maxValue: 100_000_000 })) and format on display.

How integer columns are sized

For format: 'int', the column is the smallest MySQL integer type that fits minValue/maxValue (or maxLength digits when no bounds are given). With no bounds at all, it's INT.

FieldColumn
numberField({ name: 'n' })INT(11)
numberField({ name: 'age', minValue: 0, maxValue: 150 })TINYINT UNSIGNED
numberField({ name: 'year', minValue: 1900, maxValue: 2100 })SMALLINT UNSIGNED
numberField({ name: 'delta', minValue: -1000, maxValue: 1000 })SMALLINT
numberField({ name: 'stock', minValue: 0, maxValue: 1_000_000 })MEDIUMINT UNSIGNED
numberField({ name: 'zip', maxLength: 5 })MEDIUMINT(5) (up to 99,999)
Always pair minValue with maxValue:

A missing bound is treated as "no constraint", so the smallest type wins. numberField({ name: 'views', minValue: 0 }) becomes TINYINT UNSIGNED, which caps at 255. Whenever you set minValue, also set a realistic maxValue (or leave both out to get INT).

Changing bounds later can change the column type; update-sections handles the ALTER.

minLength / maxLength: digit counts

These check the number of characters in the value, not its size. Useful for fixed-width codes:

// Exactly 6 digits: 100000–999999
numberField({ name: 'pin', minLength: 6, maxLength: 6 })

For codes with leading zeros (007, ZIP codes like 02134), use a textField instead: numbers drop leading zeros.

Auto-increment

numberField({ name: 'ticket_no', hasAutoIncrement: true })

In auto-increment mode, MySQL assigns the value:

  • The field is forced to adminGenerated: false (hidden on create, not submitted).
  • format can only be 'int' (or omitted).
  • placeholder, minValue, maxValue, minLength, maxLength, defaultValue and adminGenerated are not allowed; TypeScript and runtime validation reject them.

The default section identifier is exactly this: numberField({ name: 'id', required: true, hasAutoIncrement: true }). MySQL allows one auto-increment column per table, so don't add another when using the default identifier.

adminGenerated: 'readonly' counters

A column your website updates, visible to editors:

numberField({ name: 'download_count', label: 'Downloads', adminGenerated: 'readonly' })

Examples

Manual sort position

const position = numberField({ name: 'position', minValue: 0, maxValue: 10_000, defaultValue: 0 })

db: { table: 'slides', orderByField: position }

Percentages

numberField({ name: 'discount_percent', minValue: 0, maxValue: 100, defaultValue: 0 })
// → TINYINT UNSIGNED

Coordinates without a map

numberField({ name: 'lat', format: 'double', minValue: -90, maxValue: 90 })
numberField({ name: 'lng', format: 'double', minValue: -180, maxValue: 180 })

Storage

ColumnInteger type sized from the range, BIGINT, FLOAT, or DOUBLE; UNSIGNED when minValue >= 0
ValueA number