Configuration
The complete reference for aphex.config.ts — schemas, adapters, auth, GraphQL, versioning, branding, and security.
The aphex.config.ts file is the central configuration for your Aphex project. It's created by createCMSConfig() and wires together your schemas, database, storage, authentication, and email.
import { createCMSConfig } from '@aphexcms/cms-core/server';
import { schemaTypes } from '$lib/schemaTypes/index.js';
import { db } from '$lib/server/db/index.js';
import { authProvider } from '$lib/server/auth/index.js';
import { email } from '$lib/server/email/index.js';
export default createCMSConfig({
schemaTypes,
database: db,
email,
auth: {
provider: authProvider,
loginUrl: '/login'
},
graphql: {
defaultPerspective: 'published',
path: '/api/graphql'
},
customization: {
branding: {
title: 'My CMS'
}
}
});Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
schemaTypes | SchemaType[] | Yes | — | Your content schemas (document and object types). |
database | DatabaseAdapter | Yes | — | Database adapter instance. |
storage | StorageAdapter | null | No | Local filesystem | Storage adapter for file uploads. |
email | EmailAdapter | null | No | null | Email adapter for sending emails. |
cache | CacheAdapter | null | No | null | Cache adapter for published-perspective reads. |
auth | object | No | — | Authentication configuration. |
graphql | boolean | GraphQLConfig | No | true | GraphQL API configuration. |
versioning | object | No | — | Document version history options. |
api | (app: Hono) => void | No | — | Register custom HTTP routes / middleware on the built-in Hono app. |
customization | object | No | — | Branding and theme options. |
logLevel | string | No | auto | 'debug' in dev, 'warn' in prod. |
security | object | No | — | Security options (asset signing). |
schemaTypes
An array of SchemaType objects defining your content model. Each schema is either a document (top-level collection) or an object (reusable nested structure).
import { schemaTypes } from '$lib/schemaTypes/index.js';
createCMSConfig({
schemaTypes
// ...
});Schemas are registered in the database on first startup and re-synced when they change during development (via Vite HMR). See Schemas for the full schema reference.
database
A DatabaseAdapter instance that handles all content storage. This is the only required adapter — Aphex is database-agnostic through this interface.
import { db } from '$lib/server/db/index.js';
createCMSConfig({
database: db
// ...
});The PostgreSQL adapter (@aphexcms/postgresql-adapter) is the built-in implementation. It uses Drizzle ORM and supports Row-Level Security for multi-tenant isolation.
storage
A StorageAdapter instance for file uploads and asset management. If not provided, Aphex creates a local filesystem adapter automatically:
// Default (no config needed):
// Files stored at ./storage/assets
// Served via /assets/{id}/{filename}
// S3-compatible storage:
import { storage } from '$lib/server/storage/index.js';
createCMSConfig({
storage
// ...
});Available adapters:
- Local filesystem (default) — stores files in
./storage/assets. @aphexcms/storage-s3— S3-compatible storage (AWS S3, Cloudflare R2, MinIO).
An EmailAdapter instance for sending transactional emails (password resets, invitations, email verification). If not provided, email features are disabled.
import { email } from '$lib/server/email/index.js';
createCMSConfig({
email
// ...
});Available adapters:
@aphexcms/nodemailer-adapter— SMTP via Nodemailer. Includes acreateMailpitAdapter()shorthand for local development.@aphexcms/resend-adapter— Resend API for production.
In development, createMailpitAdapter() sends all emails to Mailpit on localhost:1025. The base template wires this up automatically — see Getting Started.
cache
An optional CacheAdapter that caches reads with perspective: 'published'. Entries are invalidated automatically when a document is published, unpublished, or deleted. Draft reads bypass the cache so the admin UI always sees the latest data.
import { InMemoryCacheAdapter } from '@aphexcms/cms-core/server';
createCMSConfig({
cache: new InMemoryCacheAdapter({ maxSize: 5000 })
});The base template exports a shared cacheAdapter from src/lib/server/cache/index.ts and passes the same instance to both the CMS config and Better Auth (for API-key lookup caching).
| Value | Behavior |
|---|---|
undefined or null | No caching (default). |
InMemoryCacheAdapter | LRU in-memory cache, shipped with @aphexcms/cms-core/server. |
Custom CacheAdapter | Implement the CacheAdapter interface for Redis, Upstash, etc. |
auth
Authentication configuration. If not provided, the CMS has no access control.
createCMSConfig({
auth: {
provider: authProvider,
loginUrl: '/login'
}
// ...
});| Option | Type | Required | Default | Description |
|---|---|---|---|---|
auth.provider | AuthProvider | Yes | — | Authentication provider instance. |
auth.loginUrl | string | No | '/login' | Redirect URL for unauthenticated users. |
The AuthProvider interface handles:
- Session auth — browser sessions for the admin UI.
- API key auth — programmatic access via
x-api-keyheader. - User management — fetching users, changing names.
- Password reset — request and confirm password resets.
The built-in integration uses Better Auth with organization support. See the scaffolded src/lib/server/auth/ directory for the full implementation.
graphql
Controls the built-in GraphQL API. Can be true (defaults), false (disabled), or a config object.
// Enabled with defaults
createCMSConfig({ graphql: true });
// Disabled
createCMSConfig({ graphql: false });
// Custom options
createCMSConfig({
graphql: {
defaultPerspective: 'published',
path: '/api/graphql',
enableGraphiQL: true,
defaultQuery: '{ allPost { id title } }'
}
});| Option | Type | Default | Description |
|---|---|---|---|
defaultPerspective | 'draft' | 'published' | 'published' | Default perspective when not specified in a query. |
path | string | '/api/graphql' | GraphQL endpoint path. |
enableGraphiQL | boolean | true | Enable the interactive GraphiQL IDE at the endpoint. |
defaultQuery | string | Built-in example | Default query shown in GraphiQL. |
See GraphQL API for the full reference.
versioning
Controls document version history. Each draft save and publish creates an entry in the cms_document_versions table. See Version History for the full reference.
createCMSConfig({
versioning: {
maxVersions: 25 // default — set 0 to disable rolling cleanup
}
});Prop
Type
api
The escape hatch for registering custom HTTP routes and middleware. Aphex's HTTP API runs on Hono — the function you pass receives the same Hono app the built-in routes mount onto, before they mount.
createCMSConfig({
api: (app) => {
// Add a brand-new endpoint
app.post('/send-email', async (c) => {
const { aphexCMS, auth } = c.var;
// ...
return c.json({ success: true });
});
// Wrap a built-in route with side effects (registration order
// matters: register before built-ins to intercept them)
app.use('/organizations/invitations', async (c, next) => {
await next();
if (c.res.status === 201) sendInviteEmail(/* ... */);
});
}
});Hono is registration-order-strict and first-match-wins. Registering before built-ins lets you
wrap them with app.use() or override them outright with app.METHOD(path, handler).
c.var exposes the same context the built-in routes use:
| Var | Type | Description |
|---|---|---|
c.var.aphexCMS | CMSInstances | Local API, services, adapters. |
c.var.auth | Auth | null | Resolved auth — session or API key. |
customization
Branding and theme options for the admin UI.
createCMSConfig({
customization: {
branding: {
title: 'My CMS',
logo: '/images/logo.png',
favicon: '/favicon.ico'
},
theme: {
colors: { primary: '#3b82f6' },
fonts: { sans: 'Inter, sans-serif' }
}
}
});Branding
| Option | Type | Default | Description |
|---|---|---|---|
title | string | 'Aphex CMS' | Display title in the admin UI. |
logo | string | — | URL to a logo image. |
favicon | string | — | URL to a favicon. |
Theme
| Option | Type | Default | Description |
|---|---|---|---|
colors | Record<string, string> | — | Custom color values (e.g. { primary: '#3b82f6' }). |
fonts | Record<string, string> | — | Custom font families (e.g. { sans: 'Inter, sans-serif' }). |
security
Security options for asset access control.
createCMSConfig({
security: {
assetSigningSecret: 'a-long-random-string-32-chars-minimum'
}
});| Option | Type | Default | Description |
|---|---|---|---|
assetSigningSecret | string | — | Secret key for HMAC-signed asset URLs. Enables temporary, expiring URLs for multi-tenant asset access without exposing API keys. Should be 32+ characters. |
How config is consumed
The createCMSHook() function in hooks.server.ts takes your config and creates singleton instances of all adapters:
import { createCMSHook } from '@aphexcms/cms-core/server';
import config from '../aphex.config.ts';
const aphexHook = createCMSHook(config);
export const handle = sequence(authHook, aphexHook);On the first request, the hook:
- Creates the storage adapter (or uses the default local filesystem).
- Initializes the
AssetServicewith the storage adapter. - Creates the
CMSEngineand registers schemas in the database. - Creates the
LocalAPI(unified data layer). - Calls your
api(app)hook (if provided), then mounts the built-in Hono routes. - Initializes GraphQL if enabled.
On every subsequent request, the hook injects these singletons into event.locals.aphexCMS, making them available in all route handlers and load functions.
What's available on event.locals.aphexCMS
event.locals.aphexCMS.localAPI; // LocalAPI instance
event.locals.aphexCMS.databaseAdapter; // DatabaseAdapter
event.locals.aphexCMS.assetService; // AssetService
event.locals.aphexCMS.storageAdapter; // StorageAdapter
event.locals.aphexCMS.emailAdapter; // EmailAdapter (or null)
event.locals.aphexCMS.cmsEngine; // CMSEngine
event.locals.aphexCMS.rolesService; // RolesService
event.locals.aphexCMS.auth; // AuthProvider (or undefined)
event.locals.aphexCMS.config; // Your resolved CMSConfig (includes `cache`, `versioning`, etc.)
event.locals.aphexCMS.graphqlSettings; // GraphQL endpoint info (or null)Last updated on