Aphex
Schema Types

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

PropertyTypeRequiredDescription
type'document'YesMust be 'document'.
namestringYesUnique identifier used in the database and API.
titlestringYesHuman-readable label shown in the admin UI.
descriptionstringNoHelp text shown in the admin sidebar.
iconLucideIconNoLucide icon component shown in the sidebar.
fieldsField[]YesArray of field definitions. See Field Types.
previewPreviewConfigNoControls how documents appear in lists.
orderingsOrdering[]NoCustom sort options for document lists.
accessSchemaAccessNoPer-operation role allowlists or policy functions. See Access Control.
singletonbooleanNoMark 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

PropertyTypeRequiredDescription
type'object'YesMust be 'object'.
namestringYesUnique identifier used when referencing this object in arrays.
titlestringYesHuman-readable label.
descriptionstringNoHelp text.
iconLucideIconNoLucide icon component.
fieldsField[]YesArray of field definitions.
previewPreviewConfigNoControls how this object appears in array lists.

Registering Schemas

All schemas must be registered in a single array and passed to createCMSConfig():

src/lib/schemaTypes/index.ts
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
];
aphex.config.ts
import { schemaTypes } from '$lib/schemaTypes/index.js';

export default createCMSConfig({
	schemaTypes
	// ...
});

Base Field Properties

Every field type shares these common properties:

PropertyTypeRequiredDescription
namestringYesUnique field identifier within the parent. Used as the data key.
typeFieldTypeYesThe field type. See below.
titlestringYesHuman-readable label shown above the field.
descriptionstringNoHelp text shown below the label.
groupstring | string[]NoGroup the field under one or more named tabs in the admin UI.
validation(Rule) => RuleNoValidation rules. Can be a single function or an array. See Validation.
accessFieldAccessNoPer-field read / update role allowlists. See Access Control.

Field Types

Aphex supports 13 built-in field types:

TypeDescriptionPage
stringSingle-line text, dropdowns, or radio buttonsString
textMulti-line textText
numberNumeric values (integers and decimals)Number
booleanTrue/false toggleBoolean
slugURL-friendly slugs with auto-generationSlug
urlURL values with format validationURL
dateDate values with calendar pickerDate
datetimeDate and time with timezone supportDatetime
imageImage uploads with alt text and metadataImage
fileGeneric file uploads (PDFs, documents, etc.)File
arrayOrdered lists of itemsArray
objectNested groups of fieldsObject
referenceLinks to other documentsReference

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:

SlotDocument listArray item rowReference pickerReference 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' }]
	}
];
Edit on GitHub

Last updated on