ChaiBuilder Logo

Configuration

A ChaiBuilder project is configured in four files, each with one job. Environment variables (database, secrets, license) are covered separately in Environment & License.

File Job
next.config.ts Next.js integration
chaibuilder.config.ts The builder's server config - plain data, importable anywhere
chaibuilder.server.ts Per-request context - auth, tenant, draft state
payload.config.ts Payload CMS + the ChaiBuilder Payload plugin

next.config.ts

Wrap your Next.js config with the ChaiBuilder wrapper (the Payload starter composes it with withPayload):

import { withChaiBuilder } from 'chaipro/nextjs'
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {}

export default withChaiBuilder(nextConfig, {
  collections: 'src/collections/**/*.{ts,tsx}',              // default
  actions: 'src/app/(builder)/**/actions/**/*.{ts,tsx}',     // default
  importMapPath: 'src/chaibuilder-import-map.ts',            // default
  watch: true,                                               // dev file watching
})

The wrapper scans your collections and actions and generates an import map at startup (and on file changes in dev). The generated file is auto-imported - never edit it by hand.

chaibuilder.config.ts

The main server config, created with buildChaiBuilderConfig. It is deliberately plain data with no framework imports, so scripts, CI, and the Payload CLI can import it.

import 'server-only'
import { buildChaiBuilderConfig } from 'chaipro/nextjs/server'

export default buildChaiBuilderConfig({
  db,                       // required - database connection (see adapters below)
  plugins: [...],           // registered plugins define the feature set
  globalDataProvider,       // data merged into every page render
  pageTypes: [...],         // dynamic page types (blog posts, docs, ...)
  collections: [...],       // collection/repeater configs
  blockDataProviders: {},   // per-block-type server data
  actions: {},              // custom server actions
  ai: { models: [...] },    // AI models offered in the builder
  debugLevel: 0,            // 0 = off | 1 = DB+HTTP | 2 = full timing+SQL
})

Options

Field Required Description
db yes Database connection from an adapter factory
plugins - Feature set: a registered plugin turns its feature on; plugin options carry its config. Nothing is auto-installed
globalDataProvider - Async provider merged into every render ({ lang, draft, inBuilder })
pageTypes - Page types with data providers; on Payload, adapt a collection directly
collections - Collections exposed to the builder
blockDataProviders - { BlockType: async provider } resolved per block instance
actions - Custom actions keyed by UPPER_SNAKE_CASE name
ai - Models list: { id, name, provider, multiplier, description } per model
debugLevel - 0, 1, or 2 - server-side cache/DB/HTTP logging

A second argument accepts onInit (runs once on first use, e.g. migrations) and extend (arbitrary values accessible on the resolved config).

Database adapters

Import the factory matching your database and pass its result as db:

Adapter Import Use
Postgres (postgres.js) chaipro/db/postgres hosted/self-managed Postgres
Postgres (node-pg pool) chaipro/db/node-pg share one pg.Pool with Payload
libSQL / Turso chaipro/db/libsql remote SQLite
SQLite (file) chaipro/db/better-sqlite3 local development, single server
Cloudflare D1 chaipro/db/d1 Workers deployments

The Payload starter uses createNodePgDB({ pool }) with a shared pool so Payload and the builder use one connection pool - see Database Setup.

Plugins

Features ship as plugins - redirects, revisions, trash, multilingual, media, roles, and more. Register server plugins in this config and their client counterparts on the builder component. Fine-grained config goes in the plugin's options:

plugins: [
  revisionsPlugin({ drafts: true }),
  redirectsPlugin(),
  mediaPlugin({ storage }),
]

chaibuilder.server.ts

Creates the request-scoped entry point every server file imports. On Payload, one line derives the whole request context (identity, tenant, draft, site URL) from Payload:

import config from '@/chaibuilder.config'
import { createPayloadChaiBuilder } from 'chaipro/payload'

export const { getChaiBuilder } = createPayloadChaiBuilder(config)

Builder access comes from the user's app membership - a Payload login by itself grants no builder access. For non-Payload auth, use createChaiBuilder(config, { context }) and resolve { appId, userId, permissions, draft, siteUrl } yourself - see API for the context contract.

payload.config.ts

Standard Payload config plus two ChaiBuilder touch points:

import { chaiBuilderPlugin, chaiBuilderSchemaHook } from 'chaipro/payload'

export default buildConfig({
  db: postgresAdapter({
    beforeSchemaInit: [chaiBuilderSchemaHook],  // merges ChaiBuilder tables into
    // Payload's schema so one migration pipeline covers both
  }),
  plugins: [
    chaiBuilderPlugin({
      menus: true,                            // menus collection for nav building
      revalidateCollections: ['blog'],        // publish here revalidates pages
      appCollections: ['blog', 'media'],      // collections scoped per app/tenant
    }),
  ],
})
chaiBuilderPlugin option Description
menus adds a menus collection editable from the builder
revalidateCollections collection slugs whose changes revalidate dependent pages - see Caching & Revalidation
appCollections collections scoped to the app/tenant

© ChaiBuilder. All rights reserved.