Skip to content

Payload Configuration

The main PayloadCMS configuration lives in src/payload.config.ts. This page covers each section of that file — what it controls and what the boilerplate defaults are.

src/payload.config.ts defines:

  • Collections and globals
  • Editor configuration
  • Admin panel settings
  • Database adapter
  • Plugin integrations
editor: lexicalEditor({
features: ({ defaultFeatures }) => {
const disabledFeatures = [
'relationship',
'horizontalRule',
'upload',
];
const enabledFeatures = defaultFeatures.filter(
(feature) => !disabledFeatures.includes(feature.key),
);
return [...enabledFeatures, FixedToolbarFeature()];
},
}),

The boilerplate starts from Lexical’s default feature set and removes three: relationship (use custom link fields instead), horizontalRule (not commonly used), and upload (use the dedicated media collection). The fixed toolbar is added so formatting controls are always visible — not hidden behind a floating menu.

admin: {
user: users.slug,
dateFormat: 'dd-MM-yyyy HH:mm',
timezones: {
defaultTimezone: 'Europe/Berlin',
},
avatar: 'default',
}

user: users.slug points Payload at the users collection for admin authentication. dateFormat controls how dates are displayed across the admin panel.

admin: {
components: {
actions: [
'/lib/payload/components/view-website/view-website#ViewWebsite',
],
header: [
'/lib/payload/components/app-environment/app-environment#AppEnvironment',
],
},
}
LocationPurpose
actionsHeader actions (e.g., “View Website” button)
headerHeader components (e.g., environment indicator)

Components are referenced by file path and named export. This avoids bundling issues with Payload’s admin panel build.

admin: {
importMap: {
baseDir: path.resolve(dirname),
},
}

This allows imports like @/components/header instead of relative paths inside admin components.

db: postgresAdapter({
pool: {
connectionString: env.DATABASE_URI,
},
beforeSchemaInit: [
({ schema, adapter }) => {
for (const tableName in adapter.rawTables) {
const table = adapter.rawTables[tableName];
for (const fieldName in table.columns) {
const column = table.columns[fieldName];
if (column.type === 'enum') {
(column as any).type = 'varchar';
}
}
}
return schema;
},
],
}),

The beforeSchemaInit hook converts enum columns to varchar. This ensures migrations work consistently across environments where enum handling can differ.

jobs: {
autoRun: [
{
cron: '*/5 * * * *',
limit: 100,
queue: '5minutes',
},
],
shouldAutoRun: async () => {
return true;
},
},

Payload’s job queue runs background tasks on a cron schedule. The default runs every 5 minutes with a batch limit of 100 jobs.

graphQL: {
disable: true,
},

GraphQL is disabled by default — the project uses Payload’s local API and REST endpoints. Set disable: false to enable it.

typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
},

Generated types are written to src/payload-types.ts. This file is committed and imported throughout the frontend for type safety. Run ddev pnpm generate:types after any config change to keep it in sync.


When adding a new collection or global, ensure:

  • Collection/global is imported
  • Fields are properly typed
  • Access control is configured
  • Revalidation hooks are added (if needed)
  • Types are regenerated