CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-payload

Node, React and MongoDB Headless CMS and Application Framework

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

configuration.mddocs/

Configuration System

Comprehensive configuration system for defining collections, globals, fields, authentication, and admin settings. The configuration serves as the foundation for your entire Payload CMS setup.

Capabilities

Configuration Builder

Core function for building and validating Payload configuration with plugin support.

/**
 * Builds and validates Payload configuration with plugin processing
 * @param config - The Payload configuration object  
 * @returns Sanitized and validated configuration
 */
function buildConfig(config: Config): SanitizedConfig;

/**
 * Plugin function type for extending Payload functionality
 */
type Plugin = (config: Config) => Config;

Usage Examples:

import { buildConfig } from "payload/config";

const config = buildConfig({
  collections: [
    // your collections
  ],
  globals: [
    // your globals  
  ],
  plugins: [
    // plugin functions that modify config
    myCustomPlugin(),
    anotherPlugin(options),
  ],
  // ... other config options  
});

// Plugin example
function myCustomPlugin(): Plugin {
  return (config: Config) => {
    // Modify and return config
    return {
      ...config,
      // Add custom collections, modify existing config, etc.
    };
  };
}

Main Configuration

The primary configuration object that defines your entire Payload setup.

/**
 * Main Payload configuration interface
 */
interface Config {
  /** Base URL for your server (required for emails and admin) */
  serverURL?: string;
  /** Array of collection configurations */
  collections?: CollectionConfig[];
  /** Array of global configurations */
  globals?: GlobalConfig[];
  /** Admin panel configuration */
  admin?: AdminConfig;
  /** Authentication configuration */
  auth?: AuthConfig;
  /** Email service configuration */
  email?: EmailConfig;
  /** File upload configuration */
  upload?: UploadConfig;
  /** Internationalization configuration */
  localization?: LocalizationConfig;
  /** TypeScript configuration */
  typescript?: TypeScriptConfig;
  /** GraphQL configuration */
  graphQL?: GraphQLConfig;
  /** CORS configuration */
  cors?: CORSConfig;
  /** CSRF protection configuration */
  csrf?: CSRFConfig;
  /** Express configuration */
  express?: ExpressConfig;
  /** API route configuration */
  routes?: {
    /** Admin panel route (default: "/admin") */
    admin?: string;
    /** API base route (default: "/api") */
    api?: string;
    /** GraphQL endpoint (default: "/api/graphql") */
    graphQL?: string;
    /** GraphQL playground route (default: "/api/graphql-playground") */
    graphQLPlayground?: string;
  };
  /** Rate limiting configuration */
  rateLimit?: RateLimitConfig;
  /** Global hooks */
  hooks?: {
    /** Hook called after errors occur */
    afterError?: AfterErrorHook;
  };
  /** Enable/disable telemetry */
  telemetry?: boolean;
  /** Enable debug mode */
  debug?: boolean;
  /** Logger configuration */
  loggerOptions?: LoggerOptions;
}

Basic Configuration Example:

import { Config } from "payload/config";

const config: Config = {
  serverURL: "http://localhost:3000",
  collections: [
    {
      slug: "posts",
      fields: [
        {
          name: "title",
          type: "text",
          required: true,
        },
        {
          name: "content",
          type: "richText",
        },
      ],
    },
  ],
  globals: [
    {
      slug: "header",
      fields: [
        {
          name: "title",
          type: "text",
        },
      ],
    },
  ],
};

export default config;

Custom Endpoints

Configuration for custom REST API endpoints that extend Payload's built-in API.

/**
 * Custom endpoint configuration
 */
interface Endpoint {
  /** URL path for the endpoint */
  path: string;
  /** HTTP method */
  method: 'get' | 'head' | 'post' | 'put' | 'patch' | 'delete' | 'connect' | 'options' | string;
  /** Handler function(s) for the endpoint */
  handler: PayloadHandler | PayloadHandler[];
}

/**
 * Payload request handler function
 */
interface PayloadHandler {
  (req: PayloadRequest, res: Response, next: NextFunction): void;
}

Usage Examples:

const config: Config = {
  // ... other config
  endpoints: [
    {
      path: '/custom-api',
      method: 'get',
      handler: (req, res, next) => {
        res.json({ message: 'Custom endpoint' });
      },
    },
    {
      path: '/webhook',  
      method: 'post',
      handler: [
        // Multiple handlers can be used
        authMiddleware,
        webhookHandler,
      ],
    },
  ],
};

Admin Panel Customization

Configuration for custom admin panel routes and components.

/**
 * Custom admin view component type
 */
type AdminView = React.ComponentType<{ 
  user: User;
  canAccessAdmin: boolean;
}>;

/**
 * Custom admin route configuration
 */
interface AdminRoute {
  /** React component to render */
  Component: AdminView;
  /** URL path for the route */
  path: string;
  /** Exact path matching (default: false) */
  exact?: boolean;
  /** Strict path matching (default: false) */
  strict?: boolean;
}

Usage Examples:

import CustomDashboard from './CustomDashboard';
import AnalyticsView from './AnalyticsView';

const config: Config = {
  // ... other config
  admin: {
    // ... other admin config
    routes: [
      {
        Component: CustomDashboard,
        path: '/custom-dashboard',
        exact: true,
      },
      {
        Component: AnalyticsView,
        path: '/analytics',
      },
    ],
  },
};

Collection Configuration

Configuration for content collections (e.g., posts, products, users).

interface CollectionConfig {
  /** Unique identifier for the collection */
  slug: string;
  /** Array of field configurations */
  fields: Field[];
  /** Display labels for the collection */
  labels?: {
    singular?: string;
    plural?: string;
  };
  /** Admin panel configuration */
  admin?: CollectionAdminConfig;
  /** Authentication configuration (makes collection auth-enabled) */
  auth?: AuthConfig | boolean;
  /** Access control rules */
  access?: CollectionAccessConfig;
  /** Collection-level hooks */
  hooks?: CollectionHooks;
  /** File upload configuration */
  upload?: UploadConfig | boolean;
  /** Document versioning configuration */
  versions?: VersionsConfig | boolean;
  /** Automatic timestamp fields */
  timestamps?: boolean;
  /** Database collection name override */
  dbName?: string;
  /** Default sort field */
  defaultSort?: string;
  /** Disable duplicate checking */
  disableDuplicate?: boolean;
  /** GraphQL configuration */
  graphQL?: {
    singularName?: string;
    pluralName?: string;
  };
  /** TypeScript configuration */
  typescript?: {
    interface?: string;
  };
}

interface CollectionAdminConfig {
  /** Default columns to show in list view */
  defaultColumns?: string[];
  /** Description shown in admin */
  description?: string;
  /** Fields to use for document preview */
  useAsTitle?: string;
  /** Custom pagination limit */
  pagination?: {
    defaultLimit?: number;
    limits?: number[];
  };
  /** List view configuration */
  listSearchableFields?: string[];
  /** Group collections in admin sidebar */
  group?: string;
  /** Hide collection from admin */
  hidden?: boolean;
  /** Disable create operation in admin */
  disableCreate?: boolean;
  /** Disable edit operation in admin */
  disableEdit?: boolean;
  /** Disable delete operation in admin */
  disableDelete?: boolean;
  /** Custom admin components */
  components?: {
    Edit?: React.ComponentType;
    List?: React.ComponentType;
  };
}

Collection Configuration Example:

const PostsCollection: CollectionConfig = {
  slug: "posts",
  labels: {
    singular: "Post",
    plural: "Posts",
  },
  admin: {
    defaultColumns: ["title", "status", "createdAt"],
    useAsTitle: "title",
    description: "Blog posts and articles",
    group: "Content",
  },
  access: {
    read: () => true,
    create: ({ req: { user } }) => !!user,
    update: ({ req: { user } }) => !!user,
    delete: ({ req: { user } }) => !!user,
  },
  fields: [
    {
      name: "title",
      type: "text",
      required: true,
    },
    {
      name: "content",
      type: "richText",
      required: true,
    },
    {
      name: "status",
      type: "select",
      options: [
        { label: "Draft", value: "draft" },
        { label: "Published", value: "published" },
      ],
      defaultValue: "draft",
    },
  ],
  hooks: {
    beforeChange: [
      ({ data, operation }) => {
        if (operation === "create") {
          data.createdBy = req.user.id;
        }
        return data;
      },
    ],
  },
  versions: {
    drafts: true,
    maxPerDoc: 10,
  },
  timestamps: true,
};

Global Configuration

Configuration for global documents (singleton content like site settings).

interface GlobalConfig {
  /** Unique identifier for the global */
  slug: string;
  /** Array of field configurations */
  fields: Field[];
  /** Display label for the global */
  label?: string;
  /** Admin panel configuration */
  admin?: GlobalAdminConfig;
  /** Access control rules */
  access?: GlobalAccessConfig;
  /** Global-level hooks */
  hooks?: GlobalHooks;
  /** Document versioning configuration */
  versions?: VersionsConfig | boolean;
  /** Automatic timestamp fields */
  timestamps?: boolean;
  /** Database collection name override */
  dbName?: string;
  /** GraphQL configuration */
  graphQL?: {
    name?: string;
  };
  /** TypeScript configuration */
  typescript?: {
    interface?: string;
  };
}

interface GlobalAdminConfig {
  /** Description shown in admin */
  description?: string;
  /** Group globals in admin sidebar */
  group?: string;
  /** Hide global from admin */
  hidden?: boolean;
  /** Custom admin components */
  components?: {
    Edit?: React.ComponentType;
  };
}

Global Configuration Example:

const HeaderGlobal: GlobalConfig = {
  slug: "header",
  label: "Site Header",
  admin: {
    description: "Configure the site header content",
    group: "Layout",
  },
  access: {
    read: () => true,
    update: ({ req: { user } }) => user?.role === "admin",
  },
  fields: [
    {
      name: "logo",
      type: "upload",
      relationTo: "media",
    },
    {
      name: "navigation",
      type: "array",
      fields: [
        {
          name: "label",
          type: "text",
          required: true,
        },
        {
          name: "url",
          type: "text",
          required: true,
        },
      ],
    },
  ],
  versions: true,
};

Access Control Configuration

Fine-grained access control for collections and globals.

interface CollectionAccessConfig {
  /** Control who can read documents */
  read?: AccessFunction;
  /** Control who can create documents */
  create?: AccessFunction;
  /** Control who can update documents */
  update?: AccessFunction;
  /** Control who can delete documents */
  delete?: AccessFunction;
  /** Control admin panel access */
  admin?: AccessFunction;
}

interface GlobalAccessConfig {
  /** Control who can read the global */
  read?: AccessFunction;
  /** Control who can update the global */
  update?: AccessFunction;
  /** Control admin panel access */
  admin?: AccessFunction;
}

type AccessFunction = (args: {
  req: PayloadRequest;
  data?: any;
  id?: string;
}) => boolean | Promise<boolean> | Where;

Access Control Examples:

// Collection access control
const access: CollectionAccessConfig = {
  // Public read access
  read: () => true,
  
  // Only authenticated users can create
  create: ({ req: { user } }) => !!user,
  
  // Users can only update their own posts
  update: ({ req: { user } }) => {
    if (user?.role === "admin") return true;
    
    return {
      author: {
        equals: user?.id,
      },
    };
  },
  
  // Only admins can delete
  delete: ({ req: { user } }) => user?.role === "admin",
  
  // Admin access based on role
  admin: ({ req: { user } }) => user?.role === "admin",
};

// Field-level access control
const titleField: Field = {
  name: "title",
  type: "text",
  access: {
    read: () => true,
    update: ({ req: { user } }) => user?.role === "admin",
  },
};

Hooks Configuration

Collection and global hooks for extending functionality.

interface CollectionHooks {
  /** Before operation hooks */
  beforeOperation?: BeforeOperationHook[];
  /** Before validation hooks */
  beforeValidate?: BeforeValidateHook[];
  /** Before change hooks */
  beforeChange?: BeforeChangeHook[];
  /** After change hooks */
  afterChange?: AfterChangeHook[];
  /** Before read hooks */
  beforeRead?: BeforeReadHook[];
  /** After read hooks */
  afterReadHook?: AfterReadHook[];
  /** Before delete hooks */
  beforeDelete?: BeforeDeleteHook[];
  /** After delete hooks */
  afterDelete?: AfterDeleteHook[];
  /** Auth-specific hooks */
  beforeLogin?: BeforeLoginHook[];
  afterLogin?: AfterLoginHook[];
  afterForgotPassword?: AfterForgotPasswordHook[];
}

type BeforeChangeHook = (args: {
  data: any;
  req: PayloadRequest;
  operation: "create" | "update";
  originalDoc?: any;
}) => any | Promise<any>;

type AfterChangeHook = (args: {
  doc: any;
  req: PayloadRequest;
  previousDoc?: any;
  operation: "create" | "update";
}) => any | Promise<any>;

Admin Configuration

Admin panel configuration and customization.

interface AdminConfig {
  /** Custom bundled admin build */
  bundler?: Bundler;
  /** Custom CSS file path */
  css?: string;
  /** Custom SCSS file path */
  scss?: string;
  /** Date display format */
  dateFormat?: string;
  /** Disable admin completely */
  disable?: boolean;
  /** Custom login logo */
  logoBg?: string;
  /** Custom login view */
  components?: {
    Nav?: React.ComponentType;
    Dashboard?: React.ComponentType;
    logout?: React.ComponentType;
  };
  /** Custom admin meta tags */
  meta?: {
    titleSuffix?: string;
    ogImage?: string;
    favicon?: string;
  };
  /** User collection slug for admin authentication */
  user?: string;
  /** Avatar configuration */
  avatar?: "default" | "gravatar" | React.ComponentType;
  /** Pagination settings */
  pagination?: {
    defaultLimit?: number;
    limits?: number[];
  };
}

Collection Hook System

Hook Types

Comprehensive hook system for extending collection behavior at different lifecycle stages.

/**
 * Collection hooks configuration
 */
interface CollectionHooks {
  /** Before any operation starts */
  beforeOperation?: BeforeOperationHook[];
  /** Before data validation */
  beforeValidate?: BeforeValidateHook[];
  /** Before data change (create/update) */
  beforeChange?: BeforeChangeHook[];
  /** After data change (create/update) */
  afterChange?: AfterChangeHook[];
  /** Before document read */
  beforeRead?: BeforeReadHook[];
  /** After document read */
  afterRead?: AfterReadHook[];
  /** Before document deletion */
  beforeDelete?: BeforeDeleteHook[];
  /** After document deletion */
  afterDelete?: AfterDeleteHook[];
  /** After operation error */
  afterError?: AfterErrorHook;
  /** Before user login (auth collections only) */
  beforeLogin?: BeforeLoginHook[];
  /** After user login (auth collections only) */
  afterLogin?: AfterLoginHook[];
  /** After user logout (auth collections only) */
  afterLogout?: AfterLogoutHook[];
  /** After "me" operation (auth collections only) */
  afterMe?: AfterMeHook[];
  /** After token refresh (auth collections only) */
  afterRefresh?: AfterRefreshHook[];
  /** After forgot password (auth collections only) */
  afterForgotPassword?: AfterForgotPasswordHook[];
}

/**
 * Hook called before any operation
 */
type BeforeOperationHook = (args: {
  /** Operation arguments */
  args?: any;
  /** Operation type being performed */
  operation: 'create' | 'read' | 'update' | 'delete' | 'login' | 'refresh' | 'logout' | 'me' | 'forgotPassword' | 'resetPassword';
}) => any;

/**
 * Hook called before data validation
 */
type BeforeValidateHook<T = any> = (args: {
  /** Document data to be validated */
  data?: Partial<T>;
  /** Express request object */
  req?: PayloadRequest;
  /** Operation type */
  operation: 'create' | 'update';
  /** Original document (for updates) */
  originalDoc?: T;
}) => any;

/**
 * Hook called before data changes are saved
 */
type BeforeChangeHook<T = any> = (args: {
  /** Document data to be saved */
  data: Partial<T>;
  /** Express request object */
  req: PayloadRequest;
  /** Operation type */
  operation: 'create' | 'update';
  /** Original document (for updates) */
  originalDoc?: T;
}) => any;

/**
 * Hook called after data changes are saved
 */
type AfterChangeHook<T = any> = (args: {
  /** Saved document */
  doc: T;
  /** Express request object */
  req: PayloadRequest;
  /** Operation type */
  operation: 'create' | 'update';
  /** Original document (for updates) */
  previousDoc?: T;
}) => void;

/**
 * Hook called before document read
 */
type BeforeReadHook = (args: {
  /** Express request object */
  req: PayloadRequest;
  /** Query arguments */
  query?: any;
}) => any;

/**
 * Hook called after document read
 */
type AfterReadHook<T = any> = (args: {
  /** Read document(s) */
  doc: T | T[];
  /** Express request object */
  req: PayloadRequest;
  /** Query arguments */
  query?: any;
}) => T | T[];

/**
 * Hook called before document deletion
 */
type BeforeDeleteHook<T = any> = (args: {
  /** Express request object */
  req: PayloadRequest;
  /** Document ID being deleted */
  id: string | number;
  /** Document being deleted */
  doc?: T;
}) => void;

/**
 * Hook called after document deletion
 */
type AfterDeleteHook<T = any> = (args: {
  /** Express request object */
  req: PayloadRequest;
  /** Document ID that was deleted */
  id: string | number;
  /** Document that was deleted */
  doc: T;
}) => void;

/**
 * Authentication-specific hooks
 */
type BeforeLoginHook<T = any> = (args: {
  /** Express request object */
  req: PayloadRequest;
  /** User attempting to login */
  user: T;
}) => void;

type AfterLoginHook<T = any> = (args: {
  /** Express request object */
  req: PayloadRequest;
  /** Logged in user */
  user: T;
  /** JWT token */
  token: string;
}) => void;

type AfterLogoutHook<T = any> = (args: {
  /** Express request object */
  req: PayloadRequest;
  /** User that logged out */
  user?: T;
}) => void;

Hook Usage Examples:

// Collection with comprehensive hooks
const PostsCollection: CollectionConfig = {
  slug: "posts",
  hooks: {
    // Log all operations
    beforeOperation: [
      ({ args, operation }) => {
        console.log(`Starting ${operation} operation`, args);
        return args;
      },
    ],
    
    // Auto-populate author field on create
    beforeChange: [
      ({ data, req, operation }) => {
        if (operation === 'create' && req.user) {
          data.author = req.user.id;
          data.createdBy = req.user.id;
        }
        if (operation === 'update' && req.user) {
          data.updatedBy = req.user.id;
        }
        return data;
      },
    ],
    
    // Generate slug from title
    beforeValidate: [
      ({ data, operation }) => {
        if ((operation === 'create' || operation === 'update') && data.title && !data.slug) {
          data.slug = data.title
            .toLowerCase()
            .replace(/[^a-z0-9]+/g, '-')
            .replace(/(^-|-$)/g, '');
        }
        return data;
      },
    ],
    
    // Clear cache after changes
    afterChange: [
      ({ doc, operation }) => {
        console.log(`${operation} completed for post: ${doc.title}`);
        // Clear cache, send notifications, etc.
        clearPostCache(doc.id);
        if (operation === 'create') {
          sendNewPostNotification(doc);
        }
      },
    ],
    
    // Filter sensitive data from reads
    afterRead: [
      ({ doc, req }) => {
        // Remove internal fields for non-admin users
        if (!req.user || req.user.role !== 'admin') {
          if (Array.isArray(doc)) {
            return doc.map(item => ({
              ...item,
              internalNotes: undefined,
              adminOnlyField: undefined,
            }));
          } else {
            return {
              ...doc,
              internalNotes: undefined,
              adminOnlyField: undefined,
            };
          }
        }
        return doc;
      },
    ],
    
    // Cleanup related data on delete
    beforeDelete: [
      async ({ req, id, doc }) => {
        // Delete related comments
        await req.payload.delete({
          collection: 'comments',
          where: {
            post: {
              equals: id,
            },
          },
        });
        
        // Log deletion
        console.log(`Deleting post: ${doc?.title} (${id})`);
      },
    ],
    
    // Post-deletion cleanup
    afterDelete: [
      ({ req, id, doc }) => {
        // Clear caches, update search indexes, etc.
        clearPostCache(id);
        updateSearchIndex();
        console.log(`Post deleted: ${doc.title}`);
      },
    ],
    
    // Handle errors
    afterError: (err, args) => {
      console.error('Collection operation failed:', err);
      // Send error to monitoring service
      sendErrorToMonitoring(err, args);
      return null;
    },
  },
  fields: [
    {
      name: "title",
      type: "text",
      required: true,
    },
    {
      name: "slug",
      type: "text",
      unique: true,
    },
    {
      name: "author",
      type: "relationship",
      relationTo: "users",
    },
  ],
};

// Auth collection with login hooks
const UsersCollection: CollectionConfig = {
  slug: "users",
  auth: true,
  hooks: {
    // Track login attempts
    beforeLogin: [
      ({ user, req }) => {
        console.log(`Login attempt for user: ${user.email}`);
        // Log to analytics, check for suspicious activity, etc.
      },
    ],
    
    // Post-login processing
    afterLogin: [
      ({ user, req, token }) => {
        console.log(`User logged in: ${user.email}`);
        // Update last login timestamp, log activity, send welcome email, etc.
        updateUserActivity(user.id, 'login');
      },
    ],
    
    // Cleanup on logout
    afterLogout: [
      ({ user, req }) => {
        if (user) {
          console.log(`User logged out: ${user.email}`);
          updateUserActivity(user.id, 'logout');
        }
      },
    ],
  },
  fields: [
    {
      name: "firstName",
      type: "text",
      required: true,
    },
    {
      name: "lastName",
      type: "text",
      required: true,
    },
  ],
};

Environment Configuration

Environment variables commonly used with Payload configuration.

// Common environment variables
interface EnvironmentVariables {
  /** Database connection string */
  DATABASE_URI?: string;
  /** Payload secret key */
  PAYLOAD_SECRET?: string;
  /** Server URL */
  PAYLOAD_PUBLIC_SERVER_URL?: string;
  /** Email service configuration */
  SMTP_HOST?: string;
  SMTP_PORT?: string;
  SMTP_USER?: string;
  SMTP_PASS?: string;
  /** File upload configuration */
  CLOUDINARY_CLOUD_NAME?: string;
  CLOUDINARY_API_KEY?: string;
  CLOUDINARY_API_SECRET?: string;
  /** Node environment */
  NODE_ENV?: "development" | "production" | "test";
}

Environment Configuration Example:

const config: Config = {
  serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || "http://localhost:3000",
  mongoURL: process.env.DATABASE_URI,
  secret: process.env.PAYLOAD_SECRET,
  email: {
    transport: {
      host: process.env.SMTP_HOST,
      port: parseInt(process.env.SMTP_PORT),
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS,
      },
    },
    fromName: "My Site",
    fromAddress: "noreply@mysite.com",
  },
};

Install with Tessl CLI

npx tessl i tessl/npm-payload

docs

authentication.md

configuration.md

core-operations.md

field-types.md

global-operations.md

index.md

preferences.md

version-control.md

tile.json