Schema Types
Define your content model with document and object types.
Schemas are TypeScript objects that define the shape of your content. Aphex reads your schemas and generates the admin UI, database structure, and API endpoints automatically.
There are two kinds of schema types:
- Document — Top-level content entities (e.g. blog posts, pages, products). Each document gets its own entry in the admin sidebar.
- Object — Reusable nested structures (e.g. SEO metadata, hero sections). Objects are embedded within documents or other objects.
Documents can also be marked as singletons — global one-of records like a site navigation or footer where only one row exists per organization.
Document Type
A document type represents a top-level content entity that is stored as its own record in the database.
import type { SchemaType } from '@aphexcms/cms-core';
import { FileText } from '@lucide/svelte';
const post: SchemaType = {
type: 'document',
name: 'post',
title: 'Blog Post',
description: 'A blog post entry.',
icon: FileText,
fields: [
{ name: 'title', type: 'string', title: 'Title' },
{ name: 'slug', type: 'slug', title: 'Slug', source: 'title' },
{ name: 'body', type: 'text', title: 'Body' }
],
preview: {
select: {
title: 'title',
subtitle: 'slug',
media: 'image'
}
},
orderings: [
{
title: 'Title A-Z',
name: 'titleAsc',
by: [{ field: 'title', direction: 'asc' }]
}
]
};Document Properties
| Property | Type | Required | Description |
|---|---|---|---|
type | 'document' | Yes | Must be 'document'. |
name | string | Yes | Unique identifier used in the database and API. |
title | string | Yes | Human-readable label shown in the admin UI. |
description | string | No | Help text shown in the admin sidebar. |
icon | LucideIcon | No | Lucide icon component shown in the sidebar. |
fields | Field[] | Yes | Array of field definitions. See Field Types. |
preview | PreviewConfig | No | Controls how documents appear in lists. |
orderings | Ordering[] | No | Custom sort options for document lists. |
access | SchemaAccess | No | Per-operation role allowlists or policy functions. See Access Control. |
singleton | boolean | No | Mark this document as a global singleton (one row per organization). See Singletons. |
Object Type
An object type defines a reusable nested structure that can be embedded inside documents or arrays.
import type { SchemaType } from '@aphexcms/cms-core';
const seo: SchemaType = {
type: 'object',
name: 'seo',
title: 'SEO Settings',
fields: [
{ name: 'metaTitle', type: 'string', title: 'Meta Title' },
{ name: 'metaDescription', type: 'text', title: 'Meta Description', rows: 3 }
]
};Object Properties
| Property | Type | Required | Description |
|---|---|---|---|
type | 'object' | Yes | Must be 'object'. |
name | string | Yes | Unique identifier used when referencing this object in arrays. |
title | string | Yes | Human-readable label. |
description | string | No | Help text. |
icon | LucideIcon | No | Lucide icon component. |
fields | Field[] | Yes | Array of field definitions. |
preview | PreviewConfig | No | Controls how this object appears in array lists. |
Registering Schemas
All schemas must be registered in a single array and passed to createCMSConfig():
import post from './post.js';
import page from './page.js';
import seo from './seo.js';
import hero from './hero.js';
export const schemaTypes = [
// Document types
post,
page,
// Object types (used inside documents and arrays)
seo,
hero
];import { schemaTypes } from '$lib/schemaTypes/index.js';
export default createCMSConfig({
schemaTypes
// ...
});Base Field Properties
Every field type shares these common properties:
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique field identifier within the parent. Used as the data key. |
type | FieldType | Yes | The field type. See below. |
title | string | Yes | Human-readable label shown above the field. |
description | string | No | Help text shown below the label. |
group | string | string[] | No | Group the field under one or more named tabs in the admin UI. |
validation | (Rule) => Rule | No | Validation rules. Can be a single function or an array. See Validation. |
access | FieldAccess | No | Per-field read / update role allowlists. See Access Control. |
Field Types
Aphex supports 13 built-in field types:
| Type | Description | Page |
|---|---|---|
string | Single-line text, dropdowns, or radio buttons | String |
text | Multi-line text | Text |
number | Numeric values (integers and decimals) | Number |
boolean | True/false toggle | Boolean |
slug | URL-friendly slugs with auto-generation | Slug |
url | URL values with format validation | URL |
date | Date values with calendar picker | Date |
datetime | Date and time with timezone support | Datetime |
image | Image uploads with alt text and metadata | Image |
file | Generic file uploads (PDFs, documents, etc.) | File |
array | Ordered lists of items | Array |
object | Nested groups of fields | Object |
reference | Links to other documents | Reference |
Preview Configuration
The preview property controls how documents and objects appear in list views — the document list (top-level documents), array item rows (object types used in array.of), and the reference picker (when another document references this one).
preview: {
select: {
title: 'name', // Field used as the primary label
subtitle: 'category', // Field used as muted secondary text
media: 'image' // Reserved for thumbnails (declared but not yet rendered)
}
}Dot-paths are supported. If your title or subtitle lives under a nested object field, address it with dot notation:
preview: {
select: {
title: 'seo.metaTitle',
subtitle: 'displayOptions.layout'
}
}The schema validator only checks that the first path segment is a real top-level field — it doesn't recurse into nested object types — so you can reference any path safely without false-positive errors.
Fallbacks when preview is omitted. If a schema has no preview block, the title slot falls through to the first non-empty value of title, heading, name, or label (in that order). The subtitle slot stays empty unless explicitly configured.
Where each slot is rendered today:
| Slot | Document list | Array item row | Reference picker | Reference selected row |
|---|---|---|---|---|
title | ✓ | ✓ | ✓ | ✓ |
subtitle | ✓ | ✓ | ✓ | ✓ |
media | — | — | — | — |
media is part of the type definition (so configuring it doesn't break anything), but the admin UI doesn't render thumbnails from it yet.
Orderings
The orderings property defines custom sort options for document lists:
orderings: [
{
title: 'Title A-Z',
name: 'titleAsc',
by: [{ field: 'title', direction: 'asc' }]
},
{
title: 'Newest First',
name: 'newestFirst',
by: [{ field: 'createdAt', direction: 'desc' }]
}
];Last updated on