# Every field type

_All 26 database field kinds, their stored values, settings, defaults, and behaviour in views and automations._

Canonical: https://snoze.dev/help/field-types/

A field is one typed property on every record in a database. Its kind decides
the value the database accepts, the editor you see, and how filters, sorts,
groups, formulas, forms, and automation tokens can use it.

<!-- GENERATED:database-field-kinds:START -->

Canonical contract values:

- `text`
- `long_text`
- `number`
- `rating`
- `date`
- `select`
- `multi_select`
- `status`
- `checkbox`
- `url`
- `email`
- `phone`
- `user`
- `file`
- `place`
- `json`
- `created_at`
- `created_by`
- `updated_at`
- `updated_by`
- `unique_id`
- `formula`
- `relation`
- `rollup`
- `time_tracking`
- `button`

<!-- GENERATED:database-field-kinds:END -->

## Settings every field shares

Every field definition has a stable ID, database and workspace IDs, a machine
key, visible label, kind, order, required flag, kind-specific `settings`, and
timestamps. An icon may be stored in settings. Choice fields additionally own
their option list, and only the generated default-value subset may own a
literal default. A required writable field must receive a value, a valid
configured default, or a supported intrinsic value when a record is created.
Read-only, computed, Button, and Time-tracking fields cannot be made required.

Views refer to the field key. Renaming a label therefore does not break a
filter or formula dependency, while deleting or changing a key can. Field
visibility and column width belong to a view rather than this shared field
definition.

## Values you can write

The writable contract is narrower than the full field list. These kinds accept
values in a record create or update. Formula, rollup, system, time-tracking, and
button values come from their own engines instead.

<!-- GENERATED:writable-database-field-kinds:START -->

Canonical contract values:

- `text`
- `long_text`
- `number`
- `rating`
- `date`
- `select`
- `multi_select`
- `status`
- `checkbox`
- `url`
- `email`
- `phone`
- `user`
- `file`
- `place`
- `json`
- `relation`

<!-- GENERATED:writable-database-field-kinds:END -->

Writable does not mean publicly collectable. Public forms deliberately exclude
people, files, places, and JSON where accepting an identifier or an opaque
payload from an anonymous visitor would be unsafe. A relation is collectable
only from the records the form itself offers. See [Every form
question type](https://snoze.dev/help/form-question-types/).

## Literal defaults

A configured default is copied into a new record when the caller omits that
field. It does not overwrite an explicit value and does not refill a field that
someone later clears. When you set or change a default, existing records whose
cell is empty get it too, so one default can fill a whole column; relation
defaults apply to new records only.

<!-- GENERATED:database-field-default-value-kinds:START -->

Canonical contract values:

- `text`
- `long_text`
- `number`
- `date`
- `select`
- `multi_select`
- `status`
- `checkbox`
- `url`
- `email`
- `phone`
- `place`
- `user`
- `relation`

<!-- GENERATED:database-field-default-value-kinds:END -->

Text-like defaults are strings; number defaults are finite numbers; checkbox
defaults are booleans. Date defaults are calendar days in `YYYY-MM-DD` form.
Select and status defaults must match an option key or name, while multi-select
uses a list of options. User and relation defaults use record or member UUIDs
and become lists when the field allows many values. File and JSON fields are
writable but cannot carry a configured literal default.

Checkbox, status, multi-select, user, file, and JSON also have intrinsic empty
shapes when a record is created: unchecked, the first status option, an empty
list where applicable, or an empty object. Those engine defaults are distinct
from a default you configure.

## Text and scalar fields

### Text `text`

Stores one string for a short value such as a name, code, or label. It has no
kind-specific settings. Filters compare either the whole value or a
case-insensitive substring; sorts use natural, case-insensitive text order, and
grouping makes one group per distinct displayed value.

### Long text `long_text`

Stores one string and uses a larger editor for notes or descriptions. Its view
behaviour is the same as Text. A record also has a block-based page body; use
that body when the content needs headings, embeds, comments, or other blocks.

### Number `number`

Stores one finite number. Display settings include number, percent, currency,
or duration formatting; zero to five displayed decimal places; and an optional
bar or ring divided by a positive maximum. The write validator also accepts a
`precision` setting from 0 to 12 for API-authored fields.

Currency formatting takes any ISO 4217 currency (`currencyCode`, default USD)
and shows its symbol before or after the amount (`currencySymbolPlacement`;
when unset, your locale's convention). Without a decimal-places choice it uses
the currency's own minor units, so USD shows cents and JPY does not. Fields
saved with the older US dollar and euro formats keep rendering as before.

Duration formatting stores the number of seconds and shows it as `h:mm`
(1:30), `h:mm:ss` (1:30:15), or compact (1h 30m). When editing, type `1:30`,
`1:30:15`, `90m`, `1h 30m`, `1.5h` or `45s`; a bare number means minutes.
Because the stored value is a plain number, sorting, filtering, and sums or
averages work as they do for any number, and totals display as durations.

The add-property menu offers Currency, Percent, Progress (a percent shown as a
bar out of 100) and Duration as ready-made number properties. Exports carry the
stored number, not the formatted text.

Number filters compare numerically. Sorts are numeric, and groups use numeric
ranges whose bucket size defaults to 100 and can be changed on the view. Number
fields can feed formula arithmetic, rollup numeric functions, chart values, and
dashboard metric aggregates.

### Rating `rating`

Stores a whole number from 0 to the field's maximum and shows it as a row of
icons, for scores a person judges at a glance: quality, fit, confidence,
priority. Settings choose the maximum, from 1 to 10 (default 5), and the icon:
star, heart, thumbs up, fire, flag, or circle (default star).

Click an icon to set the rating to that many; click the current rating again to
clear it. With a rating focused, type a digit to set it directly (0 clears) or
press Backspace or Delete to clear it. On a record page the arrow keys, Home,
and End step it; in a table, press Enter first so the arrows step the rating
instead of moving between cells, and Enter or Escape to hand them back. Values
above the maximum or with a fraction are refused rather than rounded. Lowering
the maximum keeps existing ratings: they show, filter, and total as the new
maximum, and raising it again brings back the original values.

Ratings filter and sort like numbers, group into one bucket per level (1/5 to
5/5 for a five-icon field), and feed sums and averages in formulas, rollups,
charts, and metrics. Exports and copied cells carry the rating as text such as
`3/5`, and pasting or importing `3`, `3/5`, or `★★★☆☆` sets it back. The field
stores its settings as `ratingMax` and `ratingIcon`; the assistant and MCP
tools also accept `{ max, icon }`.

### Date `date`

Stores either a parseable date/date-time string or `{ start, end }` for a range;
an end cannot precede its start. A field-level date format can be full, short,
month/day/year, day/month/year, year/month/day, or relative.

Filters and sorts use the range's start. Date is the field kind that positions
records on Calendar and Timeline views. Date grouping uses relative buckets
such as Earlier, Today, Tomorrow, Next 7 days, and Later this month, followed by
month buckets for later dates.

### Checkbox `checkbox`

Stores `true` or `false`; an omitted value becomes `false`. Filters offer
checked and unchecked explicitly. Grouping makes Checked and Unchecked groups,
and a checkbox can be used as a formula boolean, a milestone channel on a
Timeline, or a public form question.

### URL `url`

Stores one link: a URL string, or `{ "url": "…", "label": "…" }` when the link
has a display label. A link without a label is always stored as the plain
string, so older values and string-only integrations keep their exact shape.
The label is trimmed and may be at most 200 characters; an empty or `null`
label collapses the value back to the plain URL string. The URL must parse as a
URL; `javascript:`, `data:`, `vbscript:`, `blob:`, and `file:` links are
rejected, as is an object with a blank URL, a non-text label, or keys other than
`url` and `label`.

It renders as a link showing its label, or a shortened URL when it has none.
Groups and formulas use the URL, so two links to different pages never merge
because they share a label. Sorts order links by what they show: the label,
else the URL. `is` filters match the URL, while contains filters also match the
label. A public form validates the URL again before creating the record.

### Email `email`

Stores one syntactically valid email address and renders it as a mail link.
Filters, sorts, and groups treat its displayed address as text. Validation is
syntactic; it does not prove the mailbox exists.

### Phone `phone`

Stores a 3–40 character phone string containing digits and common phone
punctuation. It renders as a call link and otherwise behaves like text in a
view. Snoze does not normalise the number to a country-specific canonical form.

### Place `place`

Stores one plain string for a location. It has no coordinates, map geometry, or
place-provider identifier in the current contract, so filtering and grouping
are text-based and there is no distance query.

### JSON `json`

Stores any JSON-safe value. It is the escape hatch for provider data that does
not have a useful typed field yet. Its filter and group behaviour works on the
formatted value, not on a queryable JSON path, and it cannot be collected by a
public form or given a configured default.

## Choice fields

Select, Multi-select, and Status share ordered options. Each option has a stable
key, a visible name, a colour, and an order. Records store keys, so renaming an
option changes its display without rewriting every record. See [Select, status,
and options](https://snoze.dev/help/select-and-status-options/) for key and naming rules.

### Select `select`

Stores exactly one option key. Filters pick an option and use `is` or `is_not`;
grouping creates one group for every configured option, including empty groups,
in option order. It can drive Board columns, chart categories, and form radio,
button, or dropdown controls.

### Multi-select `multi_select`

Stores a list of option keys. Filters test whether that list contains one
option; they do not require the list to equal a complete set. Grouping currently
uses the combined formatted list as one value rather than placing a record into
several groups.

### Status `status`

Stores one option key, like Select, but expresses a lifecycle. New status
fields are normally seeded with Todo, In progress, and Done. Status grouping
defaults to manual option order, although a view may choose ascending or
descending group labels. Status or Select is required for Board columns.

## People, files, and relations

### User `user`

Stores a workspace member UUID, or a list of UUIDs when **Allow multiple** is
enabled. The editor resolves those identifiers to people. Filters accept a
member value; sorting and grouping use the formatted member value. Public forms
cannot collect this kind because exposing internal member identifiers would
cross the workspace boundary.

### File `file`

Stores a Snoze file UUID, or a list when the field is configured for multiple
files. The asset itself is owned by the file service; the field only keeps its
reference. File fields have no configured default and are excluded from public
forms, while ordinary view operations use their formatted reference value.

### Relation `relation`

Stores record UUIDs that point into one target database. Settings require the
target database and a cardinality of `one` or `many`; a reciprocal field ID is
present when the other database has a linked field back. Creating a reciprocal
relation writes both fields in one transaction.

Relation filters can test exact single-record equality or membership. Grouping
uses the formatted linked-record title; a many-valued relation therefore makes
one group for each distinct combination, not one group per linked record. A
relation enables rollups and relation-aware formulas. A public form can ask for
a relation: it offers up to 200 of the linked database's records in a
searchable dropdown, and a submission may only link records it was offered.

## System fields

System fields are populated by Snoze. You can show, hide, filter, sort, and
group them, but record writes cannot set their values and they cannot be marked
required or given defaults.

### Created at `created_at`

Stores the record creation timestamp. It accepts the date operator set and
sorts chronologically. Grouping currently uses the formatted timestamp rather
than the relative buckets used by an ordinary Date field. It never changes
after creation.

### Created by `created_by`

Stores the user ID attributed to record creation. It is read-only and uses the
general formatted-value operators for filtering, sorting, and grouping. A
system or imported write may have no creator.

### Updated at `updated_at`

Stores the last record update timestamp. It accepts date filters and
chronological sorting. Grouping currently uses the formatted timestamp rather
than the relative buckets used by an ordinary Date field. Changes to related
resources do not imply this timestamp changes unless the record itself is
updated.

### Updated by `updated_by`

Stores the user ID attributed to the last record update. Like Created by, it is
read-only and view operations use its formatted value. It may be empty when no
user can be attributed.

### Unique ID `unique_id`

Produces a stable display identifier from the first eight characters of the
record UUID, upper-cased, with an optional configured prefix. It is not an
auto-incrementing sequence and cannot be written or reset. Filters, sorts, and
groups treat the rendered identifier as text.

## Computed and interactive fields

### Formula `formula`

Evaluates an expression over the record. Settings include an expression up to
5,000 characters, a result kind of `text`, `number`, `checkbox`, `date`, or
`json`, and a compute mode of `read` or `materialized`. Snoze derives direct and
relation dependencies from the parsed expression and rejects invalid syntax or
dependency cycles.

Formula values are read-only and can feed later formulas, views, charts, and
automation record payloads. Both modes have a physical read-model value today;
the compute mode remains a query-planning hint. The view editor currently
offers Formula the general formatted-value filter operators even when its
declared result kind is numeric or date.

### Rollup `rollup`

Follows one relation field, reads one target field, and aggregates it. Required
settings are the relation field ID, target field ID, result kind, compute mode,
and one function: `count`, `count_values`, `count_empty`, `count_unique`,
`percent_empty`, `percent_not_empty`, `sum`, `average`, `median`, `range`,
`min`, `max`, `earliest`, `latest`, `checked`, `unchecked`,
`percent_checked`, `unique`, or `show_original`.

Its value is read-only and updates when its relation or target values change.
Like Formula, it can feed views and later calculations, but the view editor
currently exposes the general formatted-value filter operators rather than a
result-kind-specific set. Count functions work over any target values. Numeric
functions flatten arrays and use finite numbers, numeric strings, and booleans;
incompatible values are skipped. Earliest and latest use parseable timestamps,
checked functions count strict `true`, and unique/show-original return flattened
values before the result is coerced to the declared result kind.

### Time tracking `time_tracking`

Shows the total tracked duration for the record in milliseconds. Settings choose
`stopwatch` or `pomodoro`, a 1–480 minute Pomodoro duration, and a completion
sound: none, soft chime, digital ping, focus bell, or custom. A custom sound is
stored on each browser, not in the field.

You do not write the field value directly; time entries update it. Filters and
sorts are numeric, groups use duration buckets, and totals can feed formulas,
rollups, charts, and metrics.

### Button `button`

Stores no record value. It renders a button that invokes a workspace Action.
Settings require an action ID and may add a label, a primary, secondary, or
destructive variant, confirmation copy, and up to 50 safe input bindings from
the record ID, title, another field, or a literal.

The clicked record and configured bindings become action input. Because there
is no stored value, Button is not writable, required, defaultable, or useful as
a filter, sort, or group field even though the generic manifest can still name
it.

## Filters, sorts, groups, and conversions

See [Filtering records](https://snoze.dev/help/filtering-records/) for the generated operator
matrix and exact filter values, [Sorting records](https://snoze.dev/help/sorting-records/) for
comparison rules, and [Grouping records](https://snoze.dev/help/grouping-records/) for the
buckets each kind creates.

Changing a field kind is a data conversion, not a display-only edit. Snoze
plans the conversion and refuses one that would drop values unless the caller
explicitly accepts the loss. Hiding a field is per-view and reversible;
deleting it removes the field and its values from the database.

Database-record Automation nodes expose field values under the record's `data`
object, keyed by field key. Because the exact database schema is selected at
run time, the generic record output shape cannot name every field token in
advance; use the database-aware picker when available or a path such as
`data.status`. System and computed fields are readable downstream even though
they are not writable inputs.