Field Types Reference
Field behavior, modeling guidance, examples, and generated public contracts.
Fields define both stored data and the editing experience. Choose a field for the value you want the API to return, then use admin options to improve how editors enter it. Do not choose a storage shape solely because it looks convenient in the Admin UI.
Base properties (all fields)
Named fields use name as their stored key and should always have an explicit human-readable label. required, unique, defaultValue, access, and server hooks affect data behavior; most admin options affect presentation only.
{
name: 'title',
type: 'text',
label: 'Title',
required: true,
unique: true,
admin: { description: 'Shown as the public page heading.' },
}Required and unique indicators help editors understand constraints, but the server remains authoritative.
Internally, the public Field union is now composed of named variants such as TextField, BooleanField, SelectField, and RelationshipField. Most projects continue to use the Field union indirectly through defineCollection() and defineGlobal(), but the named variants matter for generated docs, SDK tooling, and custom type-level utilities.
Text fields
text
Use text for a single line such as a title, slug, short label, or identifier.
{
name: 'title',
type: 'text',
label: 'Title',
required: true,
admin: { placeholder: 'Enter a title…' },
}Size and word limits
maxLength and maxWords are first-class field properties for supported text inputs. The Admin UI uses them to show live character and word counters. If a write must be rejected when a limit is exceeded, enforce that in a collection or field hook for now.
{
name: 'excerpt',
type: 'textarea',
label: 'Excerpt',
maxLength: 160,
maxWords: 30,
}textarea
Use textarea for longer plain text where formatting is neither needed nor desirable.
{
name: 'summary',
type: 'textarea',
label: 'Summary',
admin: { description: 'A short plain-text summary for cards.' },
}richText
richText stores a Tiptap/ProseMirror JSON document. It is not an HTML string. Render it with a compatible rich-text renderer or transform it in a trusted server boundary.
{ name: 'body', type: 'richText', label: 'Body', required: true }email
Use email for editor-supplied email addresses. Auth collections inject their own authentication fields, so do not redefine email or password merely to enable login.
{ name: 'contactEmail', type: 'email', label: 'Contact email' }icon
The icon field stores the selected Lucide component name as a string. Resolve only known exports in the frontend and provide a fallback for names removed by an icon-library upgrade.
{ name: 'featureIcon', type: 'icon', label: 'Feature icon' }import * as icons from 'lucide-react'
export function DynamicIcon({ name }: { name: string }) {
const Icon = icons[name as keyof typeof icons]
return typeof Icon === 'function' ? <Icon aria-hidden /> : null
}url
The URL field can represent external links or internal document references. It returns a structured object, not a bare string.
{ name: 'callToAction', type: 'url', label: 'Call to action' }Stored shape
{
"type": "internal",
"url": "/blog/a-post",
"relationTo": "posts",
"value": "post-id",
"label": "Read the post"
}For external links, use the returned url. For internal links, configure the target collection's admin.urlPattern when the frontend needs a resolved URL without another fetch.
export const Posts = defineCollection({
slug: 'posts',
admin: { urlPattern: '/blog/{slug}' },
fields: [
{ name: 'title', type: 'text', label: 'Title' },
{ name: 'slug', type: 'text', label: 'Slug' },
],
})urlPattern is a frontend convenience. It does not change collection API routes.
Numeric and boolean fields
number
{ name: 'price', type: 'number', label: 'Price', defaultValue: 0 }Use a collection hook when monetary rounding, cross-field totals, or domain-specific ranges must be enforced on every write.
boolean
{
name: 'featured',
type: 'boolean',
label: 'Featured',
defaultValue: false,
admin: { layout: 'switch' },
}Checkbox and switch layouts store the same boolean value.
admin.layout is intentionally scoped here. Only boolean fields support layout: 'checkbox' | 'switch'.
Date and time fields
date
Use date when the calendar day matters but time-of-day does not.
{ name: 'eventDate', type: 'date', label: 'Event date' }datetime
Use datetime for an instant such as publication or appointment time. API values are ISO-compatible strings; be explicit about timezone presentation in the frontend.
{ name: 'publishedAt', type: 'datetime', label: 'Published at' }time
Use time for a local time-of-day whose date is modeled elsewhere.
{ name: 'openingTime', type: 'time', label: 'Opening time' }daterange appeared in older documentation but is not a current FieldType. Model a range with labeled start/end fields and validate their ordering in a collection hook.
Selection fields
select
select stores one option value. Options may be static, resolved on the server, or recalculated in the Admin UI. See Dynamic Options.
{
name: 'status',
type: 'select',
label: 'Status',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
],
}Set admin.layout: 'radio' when a small option set benefits from being visible at once.
admin.hooks.options is also scoped here. Use it for instant client-side dependent options when the available values depend on other form fields.
radio
radio is also a supported field type. Prefer it when radio-button semantics are intrinsic to the content model; use a select with radio layout when only the presentation should vary.
radio fields support admin.direction and admin.hooks.options.
multiSelect
multiSelect stores an array of option values.
{
name: 'topics',
type: 'multiSelect',
label: 'Topics',
options: ['engineering', 'design', 'business'],
}multiSelect also supports admin.hooks.options for dependent option lists.
Relationship and media fields
relationship
A relationship stores the ID of a document in another collection. Set hasMany: true to store multiple IDs.
{
name: 'author',
type: 'relationship',
label: 'Author',
relationTo: 'users',
required: true,
}At depth: 0, responses contain IDs. Higher depth hydrates related documents and increases query and payload cost. Use the lowest depth that satisfies the view.
image
image relates to upload documents and supports hasMany. It does not replace the need for an upload-enabled collection or configured storage adapter.
join
A join is a virtual reverse lookup: it stores nothing on the current document and queries documents whose relationship points back to it.
{
name: 'posts',
type: 'join',
label: 'Posts',
collection: 'posts',
on: 'author',
limit: 20,
}Use a relationship for the owning side and a join only for reverse navigation. Large joins should be bounded and indexed through the owning relationship.
Structural fields
object
Use object for a nested value with a fixed shape and the same lifecycle as its parent.
{
name: 'seo',
type: 'object',
label: 'Search metadata',
fields: [
{ name: 'title', type: 'text', label: 'Meta title' },
{ name: 'description', type: 'textarea', label: 'Meta description' },
],
}array
Use array for repeatable items with one shared shape. Use a collection instead if entries need independent IDs, access rules, querying, or reuse.
{
name: 'questions',
type: 'array',
label: 'Questions',
fields: [
{ name: 'question', type: 'text', label: 'Question', required: true },
{ name: 'answer', type: 'textarea', label: 'Answer', required: true },
],
}blocks
Blocks allow each array entry to choose a different configured shape. Keep block slugs stable and make frontend renderers handle unknown block types safely during rolling deployments.
A block may declare variants: BlockVariant[] — approved layouts that share the block's fields. Each BlockVariant has a required stable slug and optional label, icon (a Lucide name), and description. The selected slug is stored on the item under the reserved variant key and passed to your renderer as a variant prop; switching variant preserves field content, and the first variant is the default. See Presentation variants.
json
Use json for genuinely open-ended structured values. Prefer object, array, or blocks when editors and consumers benefit from an explicit contract.
Layout fields
row
row changes form layout but creates no stored wrapper. Its named children remain at the surrounding document level.
{
type: 'row',
fields: [
{ name: 'firstName', type: 'text', label: 'First name', admin: { width: '50%' } },
{ name: 'lastName', type: 'text', label: 'Last name', admin: { width: '50%' } },
],
}Admin field options
Admin options include descriptions, placeholders, conditional visibility, registered components, tabs, widths, read-only state, and filterability. They do not replace server validation or access control.
Use serializable Jexl strings for conditions that must synchronize to Dyrected Cloud:
{
name: 'scheduledAt',
type: 'datetime',
label: 'Scheduled at',
admin: { condition: "status == 'scheduled'", tab: 'Publishing' },
}Custom components are registered by string key in the framework integration. Validation, defaults, and access rules still come from the field definition.
Field access
Field read access strips denied values from API responses. Field update access ignores denied incoming changes. Enforce sensitive-data rules here or at collection access—not only with hidden or readOnly.
{
name: 'internalNotes',
type: 'textarea',
label: 'Internal notes',
access: {
read: ({ user }) => user?.roles?.includes('admin') ?? false,
update: ({ user }) => user?.roles?.includes('admin') ?? false,
},
}Field hooks
Use field hooks for transformations local to one value, including nested array/object/block values. Use collection hooks for cross-field validation or updates. Server hooks protect all API writes; Admin hooks provide editor feedback only.
See Hooks and Using Hooks.
Generated field and hook contracts
ArrayField
Exported type from @dyrected/core.
export type ArrayField = TypedField<"array", unknown>;AuthDocFields
Exported type from @dyrected/core.
export type AuthDocFields = {
email: string;
password?: string;
roles?: string[];
};AuthenticatedUser
Base shape of an authenticated user as decoded from the JWT.
The actual shape will include every field on your auth collection — this interface only guarantees the properties that Dyrected always stamps on the token. Extend it in your own codebase for stronger typing:
export interface AuthenticatedUser {
/** The user's document ID in the database. */
sub: string;
/** The user's email address. */
email?: string;
/** Slug of the collection this user was authenticated against. */
collection: string;
/** Array of role strings, if your auth collection has a `roles` field. */
roles?: string[];
/** Any additional fields from the auth collection document. */
[key: string]: unknown;
}| Member | Signature | Description |
|---|---|---|
sub | sub: string | The user's document ID in the database. |
email | email?: string | The user's email address. |
collection | collection: string | Slug of the collection this user was authenticated against. |
roles | roles?: string[] | Array of role strings, if your auth collection has a `roles` field. |
BaseFieldAdmin
Exported interface from @dyrected/core.
export interface BaseFieldAdmin {
/** Placeholder text shown when the input has no value. */
placeholder?: string;
/** Custom component key registered in the Admin UI. */
component?: string;
/** Help text rendered below the field. */
description?: string;
/** Hides the field from the Admin form without deleting stored data. */
hidden?: boolean;
/** Excludes the field from Admin list filtering. */
filterable?: boolean;
/** Renders the field as non-editable in the Admin UI. */
readOnly?: boolean;
/** Hides the field's label in the Admin form (e.g. single-field array rows where the label is redundant). */
hideLabel?: boolean;
/** Reactive condition controlling whether the field is visible in the Admin UI. */
condition?: ((data: Record<string, unknown>, siblingData: Record<string, unknown>) => boolean) | string;
/** Tab name used when the edit form is rendered as tabs. */
tab?: string;
/** CSS width hint used when the field appears inside a `row`. */
width?: string;
}| Member | Signature | Description |
|---|---|---|
placeholder | placeholder?: string | Placeholder text shown when the input has no value. |
component | component?: string | Custom component key registered in the Admin UI. |
description | description?: string | Help text rendered below the field. |
hidden | hidden?: boolean | Hides the field from the Admin form without deleting stored data. |
filterable | filterable?: boolean | Excludes the field from Admin list filtering. |
readOnly | readOnly?: boolean | Renders the field as non-editable in the Admin UI. |
hideLabel | hideLabel?: boolean | Hides the field's label in the Admin form (e.g. single-field array rows where the label is redundant). |
condition | condition?: ((data: Record<string, unknown>, siblingData: Record<string, unknown>) => boolean) | string | Reactive condition controlling whether the field is visible in the Admin UI. |
tab | tab?: string | Tab name used when the edit form is rendered as tabs. |
width | width?: string | CSS width hint used when the field appears inside a `row`. |
Block
Exported interface from @dyrected/core.
export interface Block {
/** Stable identifier stored in each block row as `blockType`. */
slug: string;
/** Human-readable labels shown in the Admin block picker. */
labels?: {
/** Singular label, for example `Hero`. */
singular: string;
/** Plural label, for example `Heroes`. */
plural: string;
};
/**
* Lucide icon name shown on the block card and in the block library.
* Falls back to a generic layout icon when omitted.
*/
icon?: AdminIconName;
/** Short one-line summary shown under the block name (block card subtitle). */
description?: string;
/**
* Presentation variants for this block. All variants share the same `fields`;
* only the rendered layout differs. The chosen variant is stored on each block
* row under the reserved `variant` key and passed to the render component as a
* `variant` prop. Switching variant preserves the author's content.
*/
variants?: BlockVariant[];
/** Fields that make up this block's payload. */
fields: Field[];
}| Member | Signature | Description |
|---|---|---|
slug | slug: string | Stable identifier stored in each block row as `blockType`. |
labels | labels?: { /** Singular label, for example `Hero`. / singular: string; /* Plural label, for example `Heroes`. */ plural: string; } | Human-readable labels shown in the Admin block picker. |
icon | icon?: AdminIconName | Lucide icon name shown on the block card and in the block library. Falls back to a generic layout icon when omitted. |
description | description?: string | Short one-line summary shown under the block name (block card subtitle). |
variants | variants?: BlockVariant[] | Presentation variants for this block. All variants share the same `fields`; only the rendered layout differs. The chosen variant is stored on each block row under the reserved `variant` key and passed to the render component as a `variant` prop. Switching variant preserves the author's content. |
fields | fields: Field[] | Fields that make up this block's payload. |
BlocksField
Exported type from @dyrected/core.
export type BlocksField = TypedField<"blocks", unknown>;BlockVariant
Exported interface from @dyrected/core.
export interface BlockVariant {
/** Stable identifier stored on the block row as `variant`. */
slug: string;
/** Human-readable label shown in the variant switcher. Defaults to `slug`. */
label?: string;
/** Lucide icon name shown beside the variant label. */
icon?: AdminIconName;
/** Short one-line summary of what this variant looks like. */
description?: string;
}| Member | Signature | Description |
|---|---|---|
slug | slug: string | Stable identifier stored on the block row as `variant`. |
label | label?: string | Human-readable label shown in the variant switcher. Defaults to `slug`. |
icon | icon?: AdminIconName | Lucide icon name shown beside the variant label. |
description | description?: string | Short one-line summary of what this variant looks like. |
BooleanField
Exported type from @dyrected/core.
export type BooleanField = TypedField<"boolean", boolean, BooleanFieldAdmin>;BooleanFieldAdmin
Exported type from @dyrected/core.
export type BooleanFieldAdmin = {
/** Boolean presentation style. */
layout?: "checkbox" | "switch";
};CharacterLimitFieldAdmin
Exported type from @dyrected/core.
export type CharacterLimitFieldAdmin = {
/** Admin-only compatibility alias for `field.maxLength`. Prefer the top-level field property. */
maxLength?: number;
};CharacterLimitFieldConfig
Exported interface from @dyrected/core.
export interface CharacterLimitFieldConfig {
/** Advisory maximum character count exposed to editors and client tooling. */
maxLength?: number;
}| Member | Signature | Description |
|---|---|---|
maxLength | maxLength?: number | Advisory maximum character count exposed to editors and client tooling. |
CollectionAfterChangeHook
Runs after a document is created or updated in the database.
export type CollectionAfterChangeHook<TDoc extends object = Record<string, unknown>> = (args: {
doc: TDoc;
previousDoc?: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
operation: "create" | "update";
db: DatabaseAdapter;
}) => void | Promise<void>;CollectionAfterDeleteHook
Runs after a document has been deleted from the database.
export type CollectionAfterDeleteHook<TDoc extends object = Record<string, unknown>> = (args: {
id: string;
doc: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
db: DatabaseAdapter;
}) => void | Promise<void>;CollectionAfterReadHook
Runs after a document (or list of documents) is fetched from the database, before the response is sent to the client.
export type CollectionAfterReadHook<TDoc extends object = Record<string, unknown>> = (args: {
doc: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
db: ReadonlyDatabaseAdapter;
}) => TDoc | Promise<TDoc>;CollectionBeforeChangeHook
Runs before a document is created or updated in the database.
export type CollectionBeforeChangeHook<TDoc extends object = Record<string, unknown>> = (args: {
data: Partial<TDoc>;
doc?: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
operation: "create" | "update";
db: ReadonlyDatabaseAdapter;
}) => Partial<TDoc> | void | Promise<Partial<TDoc> | void>;CollectionBeforeDeleteHook
Runs before a document is deleted from the database.
export type CollectionBeforeDeleteHook<TDoc extends object = Record<string, unknown>> = (args: {
id: string;
doc: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
db: ReadonlyDatabaseAdapter;
}) => void | Promise<void>;CollectionBeforeReadHook
Runs before Dyrected queries the database for a list or single-document fetch.
Return a new where query object to override or extend the current filter.
Return undefined (or nothing) to leave the query unchanged.
export type CollectionBeforeReadHook = (args: {
req: HookRequestContext;
query?: Record<string, unknown>;
user?: AuthenticatedUser;
db: ReadonlyDatabaseAdapter;
}) => Record<string, unknown> | void | Promise<Record<string, unknown> | void>;DateField
Exported type from @dyrected/core.
export type DateField = TypedField<"date", string>;DateTimeField
Exported type from @dyrected/core.
export type DateTimeField = TypedField<"datetime", string>;DynamicOptionItem
Exported type from @dyrected/core.
export type DynamicOptionItem = string | { label: string; value: unknown };DynamicOptionsConfig
Exported interface from @dyrected/core.
export interface DynamicOptionsConfig {
/** Resolver function executed on the server to produce option items. */
resolve: DynamicOptionsResolver;
/** Cache duration in seconds for identical resolver calls. */
cacheTTL?: number;
}| Member | Signature | Description |
|---|---|---|
resolve | resolve: DynamicOptionsResolver | Resolver function executed on the server to produce option items. |
cacheTTL | cacheTTL?: number | Cache duration in seconds for identical resolver calls. |
DynamicOptionsResolver
Exported type from @dyrected/core.
export type DynamicOptionsResolver = (
args: DynamicOptionsResolverArgs,
) => Promise<DynamicOptionItem[]> | DynamicOptionItem[];DynamicOptionsResolverArgs
Exported interface from @dyrected/core.
export interface DynamicOptionsResolverArgs {
/** Database adapter available to server-side option resolvers. */
db?: DatabaseAdapter;
/** Authenticated user making the request, if any. */
user?: AuthenticatedUser;
/** Current HTTP request context, including query parameters. */
req: HookRequestContext;
}| Member | Signature | Description |
|---|---|---|
db | db?: DatabaseAdapter | Database adapter available to server-side option resolvers. |
user | user?: AuthenticatedUser | Authenticated user making the request, if any. |
req | req: HookRequestContext | Current HTTP request context, including query parameters. |
EmailField
Exported type from @dyrected/core.
export type EmailField = TypedField<"email", string, EmailFieldAdmin> & CharacterLimitFieldConfig;EmailFieldAdmin
Exported type from @dyrected/core.
export type EmailFieldAdmin = CharacterLimitFieldAdmin;Field
Exported type from @dyrected/core.
export type Field =
| TextField
| TextareaField
| EmailField
| UrlField
| IconField
| DateField
| DateTimeField
| TimeField
| SelectField
| RadioField
| NumberField
| BooleanField
| MultiSelectField
| RelationshipField
| ImageField
| RichTextField
| JsonField
| ObjectField
| ArrayField
| BlocksField
| JoinField
| RowField;FieldAdminHooks
Exported type from @dyrected/core.
export type FieldAdminHooks<TValue> = {
admin?: {
hooks?: {
onChange?: FieldAdminOnChangeHook<TValue>;
};
};
};FieldAdminOnChangeHook
Exported type from @dyrected/core.
export type FieldAdminOnChangeHook<TValue = unknown> = (args: FieldAdminOnChangeHookArgs<TValue>) => unknown;FieldAdminOnChangeHookArgs
Exported interface from @dyrected/core.
export interface FieldAdminOnChangeHookArgs<TValue = unknown> {
/** Current field value in the form state. */
value: TValue;
/** Current values for sibling fields at the same nesting level. */
siblingData: Record<string, unknown>;
/** Current values for the entire form. */
data: Record<string, unknown>;
/** Imperative setter for async or derived updates. */
setValue: (value: unknown) => void;
}| Member | Signature | Description |
|---|---|---|
value | value: TValue | Current field value in the form state. |
siblingData | siblingData: Record<string, unknown> | Current values for sibling fields at the same nesting level. |
data | data: Record<string, unknown> | Current values for the entire form. |
setValue | setValue: (value: unknown) => void | Imperative setter for async or derived updates. |
FieldAdminOptionsHook
Exported type from @dyrected/core.
export type FieldAdminOptionsHook = (
args: FieldAdminOptionsHookArgs,
) => FieldAdminOptionsHookResult | Promise<FieldAdminOptionsHookResult>;FieldAdminOptionsHookArgs
Exported interface from @dyrected/core.
export interface FieldAdminOptionsHookArgs {
/** Current values for sibling fields at the same nesting level. */
siblingData: Record<string, unknown>;
/** Current values for the entire form. */
data: Record<string, unknown>;
}| Member | Signature | Description |
|---|---|---|
siblingData | siblingData: Record<string, unknown> | Current values for sibling fields at the same nesting level. |
data | data: Record<string, unknown> | Current values for the entire form. |
FieldAdminOptionsHookResult
Exported type from @dyrected/core.
export type FieldAdminOptionsHookResult = Array<string | { label: string; value: unknown }>;FieldAfterReadHook
Exported type from @dyrected/core.
export type FieldAfterReadHook<TValue = unknown, TDoc extends object = Record<string, unknown>> = (
args: FieldAfterReadHookArgs<TValue, TDoc>,
) => unknown;FieldAfterReadHookArgs
Exported interface from @dyrected/core.
export interface FieldAfterReadHookArgs<TValue = unknown, TDoc extends object = Record<string, unknown>> {
/** Raw stored field value before this hook transforms it. */
value: TValue;
/** Full document currently being returned to the caller. */
doc: TDoc;
/** Authenticated user requesting the document, if any. */
user?: AuthenticatedUser;
/** Read-only database adapter for related lookups. */
db: ReadonlyDatabaseAdapter;
}| Member | Signature | Description |
|---|---|---|
value | value: TValue | Raw stored field value before this hook transforms it. |
doc | doc: TDoc | Full document currently being returned to the caller. |
user | user?: AuthenticatedUser | Authenticated user requesting the document, if any. |
db | db: ReadonlyDatabaseAdapter | Read-only database adapter for related lookups. |
FieldBase
Exported interface from @dyrected/core.
export interface FieldBase {
/** Stored key for this field. Omit only for layout-only fields such as `row` or `join`. */
name?: string;
/** Human-readable label shown in the Admin UI. */
label?: string;
/** Whether the field must have a value when saving. */
required?: boolean;
/** Whether values for this field must be unique across the collection. */
unique?: boolean;
/** Default value used when a new document omits this field. */
defaultValue?: unknown;
/** Static or dynamic option source for supported selection fields. */
options?: string[] | { label: string; value: unknown }[] | DynamicOptionsResolver | DynamicOptionsConfig;
/** Target collection slug for `relationship` fields. */
relationTo?: string;
/** Whether the field stores multiple values instead of one. */
hasMany?: boolean;
/** Child fields for `object` and `array` field types. */
fields?: Field[];
/** Allowed block definitions for a `blocks` field. */
blocks?: Block[];
/** Target collection slug for `join` fields. */
collection?: string;
/** Back-reference field name on the joined collection. */
on?: string;
/** Maximum number of joined documents returned by a `join` field. */
limit?: number;
/** Field-level read and update access rules. */
access?: {
/** Controls whether this field is returned in API responses. */
read?: AccessFunction | string;
/** Controls whether incoming writes may change this field. */
update?: AccessFunction | string;
};
/** Admin-only presentation options for this field. */
admin?: BaseFieldAdmin;
/** Previous storage key to migrate from during schema sync. */
renameTo?: string;
/** Whether SQL adapters should promote this field into a first-class column. */
promoted?: boolean;
}| Member | Signature | Description |
|---|---|---|
name | name?: string | Stored key for this field. Omit only for layout-only fields such as `row` or `join`. |
label | label?: string | Human-readable label shown in the Admin UI. |
required | required?: boolean | Whether the field must have a value when saving. |
unique | unique?: boolean | Whether values for this field must be unique across the collection. |
defaultValue | defaultValue?: unknown | Default value used when a new document omits this field. |
options | options?: string[] | { label: string; value: unknown }[] | DynamicOptionsResolver | DynamicOptionsConfig | Static or dynamic option source for supported selection fields. |
relationTo | relationTo?: string | Target collection slug for `relationship` fields. |
hasMany | hasMany?: boolean | Whether the field stores multiple values instead of one. |
fields | fields?: Field[] | Child fields for `object` and `array` field types. |
blocks | blocks?: Block[] | Allowed block definitions for a `blocks` field. |
collection | collection?: string | Target collection slug for `join` fields. |
on | on?: string | Back-reference field name on the joined collection. |
limit | limit?: number | Maximum number of joined documents returned by a `join` field. |
access | access?: { /** Controls whether this field is returned in API responses. / read?: AccessFunction | string; /* Controls whether incoming writes may change this field. */ update?: AccessFunction | string; } | Field-level read and update access rules. |
admin | admin?: BaseFieldAdmin | Admin-only presentation options for this field. |
renameTo | renameTo?: string | Previous storage key to migrate from during schema sync. |
promoted | promoted?: boolean | Whether SQL adapters should promote this field into a first-class column. |
FieldBeforeChangeHook
Exported type from @dyrected/core.
export type FieldBeforeChangeHook<TValue = unknown, TDoc extends object = Record<string, unknown>> = (
args: FieldBeforeChangeHookArgs<TValue, TDoc>,
) => unknown;FieldBeforeChangeHookArgs
Exported interface from @dyrected/core.
export interface FieldBeforeChangeHookArgs<TValue = unknown, TDoc extends object = Record<string, unknown>> {
/** Current field value after previous hooks in the chain. */
value: TValue;
/** Existing stored document before the write, if this is an update. */
originalDoc?: TDoc;
/** Full incoming payload being written. */
data: Record<string, unknown>;
/** Authenticated user performing the write, if any. */
user?: AuthenticatedUser;
/** Read-only database adapter for related lookups. */
db: ReadonlyDatabaseAdapter;
}| Member | Signature | Description |
|---|---|---|
value | value: TValue | Current field value after previous hooks in the chain. |
originalDoc | originalDoc?: TDoc | Existing stored document before the write, if this is an update. |
data | data: Record<string, unknown> | Full incoming payload being written. |
user | user?: AuthenticatedUser | Authenticated user performing the write, if any. |
db | db: ReadonlyDatabaseAdapter | Read-only database adapter for related lookups. |
FieldHook
Exported type from @dyrected/core.
export type FieldHook<TDoc extends object = Record<string, unknown>, TValue = unknown> = FieldBeforeChangeHook<
TValue,
TDoc
>;FieldHooks
Exported type from @dyrected/core.
export type FieldHooks<TValue> = {
hooks?: {
beforeChange?: Array<FieldBeforeChangeHook<TValue>>;
afterRead?: Array<FieldAfterReadHook<TValue>>;
};
};FieldType
Exported type from @dyrected/core.
export type FieldType =
| "text"
| "textarea"
| "richText"
| "number"
| "boolean"
| "date"
| "datetime"
| "time"
| "select"
| "multiSelect"
| "radio"
| "relationship"
| "array"
| "object"
| "json"
| "blocks"
| "image"
| "email"
| "url"
| "icon"
| "join"
| "row";GlobalAfterChangeHook
Runs after the global document is updated. Side-effects only.
export type GlobalAfterChangeHook<TDoc extends object = Record<string, unknown>> = (args: {
doc: TDoc;
previousDoc?: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
operation: "update";
db: DatabaseAdapter;
}) => void | Promise<void>;GlobalAfterReadHook
Runs after the global document is fetched, before the response is sent.
export type GlobalAfterReadHook<TDoc extends object = Record<string, unknown>> = (args: {
doc: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
db: ReadonlyDatabaseAdapter;
}) => TDoc | Promise<TDoc>;GlobalBeforeChangeHook
Runs before the global document is updated.
Operation is always 'update' (globals cannot be created or deleted).
export type GlobalBeforeChangeHook<TDoc extends object = Record<string, unknown>> = (args: {
data: Partial<TDoc>;
doc?: TDoc;
req: HookRequestContext;
user?: AuthenticatedUser;
operation: "update";
db: ReadonlyDatabaseAdapter;
}) => Partial<TDoc> | void | Promise<Partial<TDoc> | void>;GlobalBeforeReadHook
Exported type from @dyrected/core.
export type GlobalBeforeReadHook = CollectionBeforeReadHook;HookFunction
Exported type from @dyrected/core.
export type HookFunction<TDoc extends object = Record<string, unknown>> = (args: {
data?: Partial<TDoc>;
doc?: TDoc;
user?: AuthenticatedUser;
req?: HookRequestContext;
operation?: "create" | "update" | "delete";
db?: DatabaseAdapter;
[key: string]: unknown;
}) => unknown | Promise<unknown>;HookRequestContext
Minimum HTTP request context passed to every server-side hook and resolver.
The full Web Standard Request is available as raw when you need it, but
most hooks only need query (URL search parameters).
export interface HookRequestContext {
/** Parsed URL query-string parameters, e.g. `{ page: '2', search: 'hello' }`. */
query: Record<string, string>;
/** Incoming HTTP headers, lowercased. */
headers: Record<string, string>;
/** The raw Web Standard `Request` object. Useful for streaming or advanced header inspection. */
raw?: Request;
}| Member | Signature | Description |
|---|---|---|
query | query: Record<string, string> | Parsed URL query-string parameters, e.g. `{ page: '2', search: 'hello' }`. |
headers | headers: Record<string, string> | Incoming HTTP headers, lowercased. |
raw | raw?: Request | The raw Web Standard `Request` object. Useful for streaming or advanced header inspection. |
IconField
Exported type from @dyrected/core.
export type IconField = TypedField<"icon", string, IconFieldAdmin> & CharacterLimitFieldConfig;IconFieldAdmin
Exported type from @dyrected/core.
export type IconFieldAdmin = CharacterLimitFieldAdmin;ImageField
Exported type from @dyrected/core.
export type ImageField = TypedField<"image", string | string[]>;InferDocShape
Exported type from @dyrected/core.
export type InferDocShape<Fields extends readonly Field[]> = Fields extends readonly []
? Record<never, never>
: Fields extends readonly [infer Head extends Field, ...infer Tail extends readonly Field[]]
? InferFieldEntry<Head> & InferDocShape<Tail>
: Record<string, unknown>;JoinField
Exported type from @dyrected/core.
export type JoinField = TypedField<"join", unknown>;JsonField
Exported type from @dyrected/core.
export type JsonField = TypedField<"json", Record<string, unknown>>;MultiSelectField
Exported type from @dyrected/core.
export type MultiSelectField = TypedField<"multiSelect", string[], MultiSelectFieldAdmin>;MultiSelectFieldAdmin
Exported type from @dyrected/core.
export type MultiSelectFieldAdmin = {
hooks?: {
/** Client-side option recalculation for dependent multi-select fields. */
options?: FieldAdminOptionsHook;
};
};NumberField
Exported type from @dyrected/core.
export type NumberField = TypedField<"number", number>;ObjectField
Exported type from @dyrected/core.
export type ObjectField = TypedField<"object", unknown>;RadioField
Exported type from @dyrected/core.
export type RadioField = TypedField<"radio", string, RadioFieldAdmin>;RadioFieldAdmin
Exported type from @dyrected/core.
export type RadioFieldAdmin = {
/** Radio group orientation. */
direction?: "horizontal" | "vertical";
hooks?: {
/** Client-side option recalculation for dependent radio groups. */
options?: FieldAdminOptionsHook;
};
};RelationshipField
Exported type from @dyrected/core.
export type RelationshipField = TypedField<"relationship", string | string[]>;RichTextField
Exported type from @dyrected/core.
export type RichTextField = TypedField<"richText", Record<string, unknown>>;RowField
Exported type from @dyrected/core.
export type RowField = TypedField<"row", unknown>;SelectField
Exported type from @dyrected/core.
export type SelectField = TypedField<"select", string, SelectFieldAdmin>;SelectFieldAdmin
Exported type from @dyrected/core.
export type SelectFieldAdmin = {
/** Select presentation style. */
layout?: "radio" | "select";
/** Radio orientation when `layout: 'radio'` is used. */
direction?: "horizontal" | "vertical";
hooks?: {
/** Client-side option recalculation for dependent dropdowns or radios. */
options?: FieldAdminOptionsHook;
};
};SystemDocFields
Exported type from @dyrected/core.
export type SystemDocFields = {
createdAt?: string;
updatedAt?: string;
createdBy?: string;
updatedBy?: string;
};TextareaField
Exported type from @dyrected/core.
export type TextareaField = TypedField<"textarea", string, TextareaFieldAdmin> &
CharacterLimitFieldConfig &
WordLimitFieldConfig;TextareaFieldAdmin
Exported type from @dyrected/core.
export type TextareaFieldAdmin = CharacterLimitFieldAdmin & WordLimitFieldAdmin;TextField
Exported type from @dyrected/core.
export type TextField = TypedField<"text", string, TextFieldAdmin> & CharacterLimitFieldConfig & WordLimitFieldConfig;TextFieldAdmin
Exported type from @dyrected/core.
export type TextFieldAdmin = CharacterLimitFieldAdmin & WordLimitFieldAdmin;TimeField
Exported type from @dyrected/core.
export type TimeField = TypedField<"time", string>;TypedField
Exported type from @dyrected/core.
export type TypedField<TType extends FieldType, TValue, TAdminExtra = Record<never, never>> = Omit<FieldBase, "admin"> & {
type: TType;
admin?: BaseFieldAdmin & TAdminExtra;
} & FieldHooks<TValue> &
FieldAdminHooks<TValue>;UploadDocFields
Exported type from @dyrected/core.
export type UploadDocFields = {
filename: string;
filesize?: number;
mimeType: string;
url: string;
width?: number;
height?: number;
focalPoint?: { x: number; y: number };
blurhash?: string;
sizes?: Record<string, { filename?: string; url?: string; width?: number; height?: number }>;
};UrlField
Exported type from @dyrected/core.
export type UrlField = TypedField<"url", string, UrlFieldAdmin> & CharacterLimitFieldConfig;UrlFieldAdmin
Exported type from @dyrected/core.
export type UrlFieldAdmin = CharacterLimitFieldAdmin;WordLimitFieldAdmin
Exported type from @dyrected/core.
export type WordLimitFieldAdmin = {
/** Admin-only compatibility alias for `field.maxWords`. Prefer the top-level field property. */
maxWords?: number;
};WordLimitFieldConfig
Exported interface from @dyrected/core.
export interface WordLimitFieldConfig {
/** Advisory maximum word count exposed to editors and client tooling. */
maxWords?: number;
}| Member | Signature | Description |
|---|---|---|
maxWords | maxWords?: number | Advisory maximum word count exposed to editors and client tooling. |