Configuration API
Companions:
- Configuration — which application files own these objects and which runtime imports each one.
- Collections API — the collection tuple and the server/client presentation registries configured here.
- Core composition — initialization order, validation, adapters, and package boundaries.
- Client-config registration — the dual admin registration path used by the TanStack Start host.
This is the exact application-facing configuration surface from @byline/core and the request-bound client getter surface from @byline/client/server. Use it when wiring byline/server.config.ts, byline/admin.config.ts, or server-side application reads.
BaseConfig
BaseConfig contains the configuration shared by the server and admin. The server and client configs extend it independently.
interface BaseConfig { serverURL: string i18n: I18nConfig collections: readonly CollectionDefinition[] routes?: RoutesConfigInput}Property | Required | Description |
| Yes | Absolute origin used when Byline needs the configured host URL. The reference app reads |
| Yes | Admin-interface locales, content locales, display labels, and admin translation bundles. |
| Yes | Canonical readonly collection tuple. The server and admin must receive the same schema definitions. |
| No | Partial admin, API, and sign-in mount paths. |
i18n
interface I18nConfig { interface: { defaultLocale: string locales: string[] localeDefinitions?: ReadonlyArray<{ code: string; nativeName: string }> } content: { defaultLocale: string locales: string[] localeDefinitions?: ReadonlyArray<{ code: string; nativeName: string }> } translations?: TranslationBundleShape}Property | Required | Description |
| Yes | Fallback locale for the admin interface. It must be present in |
| Yes | Permitted admin-interface locale codes. Every declared code requires at least one registered translation namespace. |
| No | Display labels used by the admin language switcher. Missing codes fall back through |
| Yes | Source locale assigned to newly created documents and the default locale for reads that do not specify one. Existing documents retain their own |
| Yes | Content locales the installation can author and serve. |
| No | Host-authored display labels for public content-language affordances. Byline stores and exposes them but does not render them itself. |
| Conditional | Locale → namespace → key → ICU message string. Required at boot when |
The complete behavioral model is in Internationalization.
RoutesConfigInput
interface RoutesConfigInput { admin?: string api?: string signIn?: string}Property | Default | Description |
|
| Root of the Byline admin route tree. |
|
| Root reserved for Byline API-facing routes. |
|
| Sign-in route outside both the admin and API trees. |
resolveRoutes(input?) normalizes repeated and missing slashes, rejects query/hash/encoded/unsafe paths, rejects . and .. segments, requires non-overlapping route trees, and returns a frozen RoutesConfig with all three keys.
import { resolveRoutes } from '@byline/core'
export const routes = resolveRoutes({ admin: '/cms', api: '/api', signIn: '/cms-sign-in',})Changing this object does not rename the physical host route files. Routing and API documents that coordination boundary.
ClientConfig
ClientConfig extends BaseConfig with admin presentation and browser-side adapter slots. It may contain React component references and must remain outside public route bundles.
interface ClientConfig extends BaseConfig { admin?: CollectionAdminConfig[] blockAdmin?: BlockAdminConfig[] slugifier?: SlugifierFn fields?: { richText?: { editor: RichTextEditorComponent } }}Property | Default | Description |
|
| Collection presentation configs registered by |
|
| Site-wide block presentation configs registered by |
|
| Client copy used by the admin path widget for live previews. Register the same pure synchronous function on |
| None | React editor component used for rich-text fields unless a per-field admin config overrides it. Rich-text fields in the admin require a registered editor. |
import { type ClientConfig, defineClientConfig } from '@byline/core'
export const config: ClientConfig = { serverURL, i18n, routes, collections, admin: [DocsAdmin, NewsAdmin, PagesAdmin], blockAdmin: [QuoteBlockAdmin, PhotoBlockAdmin], fields: { richText: { editor: LexicalRichTextAi } },}
defineClientConfig(config)defineClientConfig(config)
function defineClientConfig(config: ClientConfig): ResolvedClientConfigValidates collection, collection-admin, and block-admin registrations; resolves routes; registers the client singleton in the current module graph; and returns the resolved object.
getClientConfig()
function getClientConfig(): ResolvedClientConfigReturns the registered client config. During server-side rendering, if only a server config is available, it returns a compatible fallback containing the shared configuration, admin: [], and the server slugifier. It throws when neither config exists.
ServerConfig
ServerConfig<TAdminStore> extends BaseConfig with server-only implementations. initBylineCore() is the normal registration entry point.
interface ServerConfig<TAdminStore = unknown> extends BaseConfig { db: IDbAdapter hooks?: ServerHooksConfig storage?: IStorageProvider slugifier?: SlugifierFn uploads?: { filenameSlugifier?: FilenameSlugifierFn } sessionProvider?: SessionProvider adminStore?: TAdminStore fields?: { richText?: { populate?: RichTextPopulateFn embed?: RichTextEmbedFn toMarkdown?: RichTextToMarkdownFn toText?: RichTextToTextFn } } search?: SearchProvider}Property | Requirement or default | Description |
| Required | Database adapter implementing typed storage, transactions, audit operations, collection bootstrap, and tree operations when used. |
| Optional | Server-only collection and upload hook registry attached after configuration validation. |
| Conditional | Installation-wide upload storage fallback. Required when an upload field has no |
|
| Authoritative document-path slugifier. Must be pure, synchronous, and identical to the client copy when customized. |
|
| Server-only transformation for the human-readable base name of every uploaded file before hooks and provider key composition. |
| Optional in the type | Authentication session implementation. Admin sign-in, refresh, verification, and revocation require one. |
| Optional | Adapter-built admin repositories surfaced on |
| Conditional | Write-time rich-text relation embedder. Required when a rich-text field effectively enables |
| Conditional | Read-time rich-text relation refresher. Required when a rich-text field effectively enables |
| Optional | Synchronous one-way serializer used by markdown document export, |
| Conditional | Plain-text extractor required when a collection search body includes a rich-text field. |
| Conditional | Search provider required when any collection declares |
ServerHooksConfig
interface ServerHooksConfig { collections?: Record<string, CollectionHooks | CollectionHooksLoader> uploads?: Record<string, UploadHooks | UploadHooksLoader>}Property | Key | Description |
| Collection path, such as | Hooks merged onto that collection after initialization validates the registry. |
|
| Field-scoped upload hooks. Array indexes are omitted; a block type segment follows a blocks field. |
export const serverHooks: ServerHooksConfig = { collections: { docs: () => import('./docs/hooks.js'), }, uploads: { 'media.image': () => import('./media/upload-hooks.js'), },}Use this registry when the hook module imports Node-only packages, secrets, storage SDKs, or server clients. A loader attached directly to an isomorphic schema remains reachable from the browser graph.
initBylineCore(config, pinoLogger?)
async function initBylineCore<TAdminStore = unknown>( config: ServerConfig<TAdminStore>, pinoLogger?: pino.Logger): Promise<BylineCore<TAdminStore>>This is the recommended server entry point. It:
- resolves and validates configuration;
- validates rich-text, search, translations, tree capabilities, and collection definitions;
- composes the configured services and logger;
- reconciles collection records and schema versions;
- ensures counter sequences and backfills legacy source locales where supported;
- registers collection abilities; and
- commits the server config, logger, and core singletons only after initialization succeeds.
defineServerConfig(config)
function defineServerConfig<TAdminStore = unknown>( config: ServerConfig<TAdminStore>): ResolvedServerConfig<TAdminStore>Validates, resolves routes, attaches configured hooks, and registers only the server-config singleton. It does not compose a BylineCore, reconcile collections, or register the logger and abilities. Application bootstraps should normally use initBylineCore().
getServerConfig()
function getServerConfig(): ResolvedServerConfigReturns the registered server config. It throws in a browser or before server configuration has completed.
BylineCore
initBylineCore() returns and globally registers the composed runtime.
Property or method | Type | Description |
|
| Resolved server configuration. |
|
| Canonical configured collection tuple. |
|
| Configured database adapter. |
|
| Installation-wide storage provider. |
|
| Structured runtime logger. |
|
| Boot-reconciled collection IDs, versions, and fingerprints by path. |
|
| Throwing cached lookup for one registered collection. |
|
| Collection and application ability registry. |
|
| Adds an application or plugin ability. |
|
| Returns every registered ability. |
|
| Groups registered abilities for admin presentation. |
|
| Configured session provider. |
|
| Configured admin-store aggregate. |
getBylineCore<TAdminStore>()
function getBylineCore<TAdminStore = unknown>(): BylineCore<TAdminStore>Returns the core registered by initBylineCore(). It throws in the browser or before initialization completes.
Configuration lookup helpers
Function | Return | Behavior |
|
| Reads the current server config, or client config when no server config exists, and finds a schema by path. |
|
| Finds one client-side collection admin config by slug. Returns |
|
| Returns |
|
| Returns a sorted copy using configured content-locale order, with unknown codes alphabetized at the end. It never filters codes. |
Server client getters
The @byline/client/server subpath is server-only. Its browser export condition throws.
Function | Request authority | Use |
| Anonymous published reader | Feeds, sitemaps, third-party endpoints, and public reads where preview must never apply. |
| Anonymous by default; admin actor when a preview cookie and valid admin session both resolve | Public pages that support editorial preview. The call still needs |
| Authenticated admin actor resolved from the current request | Admin server functions and request-bound admin reads/writes. |
| Stable super-admin system actor | Seeds, migrations, maintenance jobs, and background lifecycle work outside an HTTP request. |
| — | Resolves |
import { getViewerBylineClient, isPreviewActive } from '@byline/client/server'
const preview = await isPreviewActive()const page = await getViewerBylineClient().collection('pages').findByPath('about', { status: preview ? 'any' : 'published',})All getters cache the client instance but resolve request authority per operation. Generated Register augmentation types every getter with the application's collection paths and field shapes.