payloadcms/payload
Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.
Builds TypeScript fullstack applications with instant backend APIs and admin panels using Next.js
Data flows through Payload in multiple patterns: Configuration-driven setup loads user configs and generates database schemas and API routes. Request processing parses incoming HTTP/GraphQL requests, applies access control and validation, executes database operations through adapters, runs hooks, and returns formatted responses. Content creation flows from admin UI forms through validation, hooks, storage adapters for files, and database persistence. The system maintains type safety throughout by generating TypeScript types from configurations.
Under the hood, the system uses 4 feedback loops, 4 data pools, 5 control points to manage its runtime behavior.
A 10-component fullstack. 6311 files analyzed. Data flows through 7 distinct pipeline stages.
How Data Flows Through the System
Data flows through Payload in multiple patterns: Configuration-driven setup loads user configs and generates database schemas and API routes. Request processing parses incoming HTTP/GraphQL requests, applies access control and validation, executes database operations through adapters, runs hooks, and returns formatted responses. Content creation flows from admin UI forms through validation, hooks, storage adapters for files, and database persistence. The system maintains type safety throughout by generating TypeScript types from configurations.
- Load Configuration — The Payload constructor reads payload.config.ts file, validates collection and global configurations, initializes plugins, and sets up the runtime configuration object that drives all subsequent operations
- Generate Database Schema — SchemaGenerator transforms collection field definitions into database-specific table schemas through the selected DatabaseAdapter, creating tables, indexes, and relationships based on field configurations [PayloadConfig]
- Process API Request — CollectionRouter receives HTTP requests, parses query parameters and request bodies, validates against collection access rules, and constructs AdapterQuery objects for database operations
- Execute Database Operation — DatabaseAdapter translates AdapterQuery into database-specific queries (SQL for Drizzle, MongoDB queries for Mongoose), executes them with proper transactions, and returns raw database results [AdapterQuery → DatabaseDocument]
- Run Lifecycle Hooks — HookRunner executes user-defined hooks (beforeCreate, afterRead, etc.) at operation boundaries, allowing custom validation, data transformation, and side effects like sending emails or updating external services [DatabaseDocument → DatabaseDocument]
- Handle File Uploads — For upload-enabled collections, StorageAdapter processes file buffers, stores them via configured provider (S3, local filesystem), generates serving URLs, and saves metadata to the database [StorageFile → DatabaseDocument]
- Format API Response — Response formatters transform DatabaseDocument results into JSON responses, applying field-level access control, population of relationships, and locale-specific data for internationalized content [DatabaseDocument]
Data Models
The data structures that flow between stages — the contracts that hold the system together.
packages/payload/src/config/types.tsConfiguration object with collections: CollectionConfig[], globals: GlobalConfig[], db: DatabaseAdapter, admin: AdminConfig, and plugins: Plugin[] defining the entire CMS structure
Loaded at startup from user's payload.config.ts, validated and transformed into runtime configuration, then used to generate database schemas, API routes, and admin UI
packages/payload/src/collections/config/types.tsCollection definition with slug: string, fields: Field[], access: AccessControl, hooks: Hooks, upload?: UploadConfig defining content types
Defined in config files, processed into database tables/collections, generates CRUD endpoints and admin forms
packages/payload/src/database/types.tsGeneric document structure with id: string|number, createdAt: Date, updatedAt: Date plus user-defined fields from collection configuration
Created through admin UI or API, stored via database adapter, retrieved and transformed for client consumption
packages/drizzle/src/types.tsDatabase query object with where: WhereConditions, sort: SortOptions, limit: number, populate: PopulateOptions translated from REST/GraphQL params
Built from incoming API requests, passed to database adapter for execution, results transformed back to API format
packages/email-nodemailer/src/index.tsEmail payload with to: string, from: string, subject: string, text?: string, html?: string for transactional messaging
Generated by auth hooks and user workflows, processed by email adapter, delivered via configured transport
packages/plugin-cloud-storage/src/types.tsFile metadata with filename: string, mimeType: string, size: number, buffer: Buffer for upload processing
Uploaded through admin UI, processed by storage adapter, metadata saved to media collections
Hidden Assumptions
Things this code relies on but never validates. These are the things that cause silent failures when the system changes.
All safe string values match SAFE_STRING_REGEX pattern and any value not matching this regex is dangerous for SQL injection
If this fails: If SAFE_STRING_REGEX is too restrictive, legitimate user data gets rejected with 400 errors. If too permissive, SQL injection vulnerabilities slip through the sanitization
packages/drizzle/src/postgres/createJSONQuery/index.ts:sanitizeValue
pathSegments array always has at least one element and pathSegments[0] contains the root field name
If this fails: If pathSegments is empty, pathSegments.slice(1) works but fullPath becomes '$[*]' and pathSegments.length === 1 check fails, generating malformed JSON path queries
packages/drizzle/src/postgres/createJSONQuery/index.ts:createJSONQuery
findMigrationDir function returns a valid directory path that exists and is writable for migration files
If this fails: If migration directory doesn't exist or lacks write permissions, adapter initialization silently continues but migration operations fail later with filesystem errors
packages/db-postgres/src/index.ts:adapter
The Promise resolution/rejection callbacks (resolveInitializing/rejectInitializing) will be called exactly once during adapter initialization
If this fails: If initialization code paths don't call these callbacks, API requests hang forever waiting for the adapter to be ready
packages/db-postgres/src/index.ts:initializing
drizzle-kit is available as a runtime dependency when migration operations are called
If this fails: Migration commands fail with module not found errors if drizzle-kit is only installed as devDependency or missing entirely
packages/db-postgres/src/index.ts:requireDrizzleKit
Arrays passed to 'in'/'not_in' operators have reasonable length that won't exceed PostgreSQL's expression limits
If this fails: Very large arrays generate massive OR/AND chains that exceed PostgreSQL's maximum expression depth, causing query compilation errors
packages/drizzle/src/postgres/createJSONQuery/index.ts:createJSONQuery
sanitizePathSegment function properly escapes all path segment characters that have special meaning in PostgreSQL JSONPath expressions
If this fails: If path segments contain unescaped JSONPath metacharacters like $, @, ?, query syntax breaks or behaves unexpectedly
packages/drizzle/src/postgres/createJSONQuery/index.ts:sanitizePathSegment
Upload configuration imageSizes array contains objects with exactly 'name', 'height', and 'width' properties of correct types
If this fails: If imageSize objects have wrong property names, missing dimensions, or non-numeric sizes, file upload processing fails or generates broken image variants
test/admin-bar/collections/Media/index.ts:MediaCollection
afterCreateConnection callback, if provided, completes successfully and doesn't throw exceptions during database initialization
If this fails: If the callback throws errors, MongoDB adapter initialization fails without clear error messages about which custom logic caused the failure
packages/db-mongodb/src/index.ts:Args.afterCreateConnection
The dist/index.js file exists and exports a main function when the CLI binary executes
If this fails: If TypeScript compilation fails or output directory changes, the CLI command fails with module resolution errors
packages/create-payload-app/bin/cli.js
System Behavior
How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
Primary data store where all documents, users, globals, and media metadata accumulate, organized by collection schemas with relationships and indexes
Runtime registry holding collection configs, global configs, plugin configurations, and field schemas that drive system behavior
External storage systems (S3, GCS, local filesystem) that accumulate uploaded files and media assets with URL-based access
JWT tokens and session data that accumulate during user authentication and maintain login state across requests
Feedback Loops
- Configuration Hot Reload (polling, reinforcing) — Trigger: File system changes to payload.config.ts in development mode. Action: Re-loads configuration, regenerates schemas, and restarts API routes without full application restart. Exit: Production mode or manual stop.
- Hook Chain Execution (recursive, reinforcing) — Trigger: Database operations (create, update, delete) on collections. Action: Executes beforeOperation hooks, performs database write, then executes afterOperation hooks which may trigger additional operations. Exit: All hooks complete successfully or error thrown.
- Database Transaction Retry (retry, balancing) — Trigger: Database adapter operations failing due to conflicts or timeouts. Action: Rolls back transaction, waits with exponential backoff, retries operation up to configured maximum attempts. Exit: Operation succeeds or maximum retries exceeded.
- Plugin Dependency Resolution (recursive, reinforcing) — Trigger: Plugin initialization during config loading. Action: Each plugin may register additional collections or modify existing ones, which can trigger other plugins to activate or reconfigure. Exit: All plugin dependencies resolved and no circular dependencies detected.
Delays
- Database Connection Pool (async-processing, ~Variable based on connection availability) — API requests queue until database connections become available from the pool
- File Upload Processing (async-processing, ~Depends on file size and storage provider latency) — Upload endpoints stream file data to storage providers while generating metadata and thumbnails
- Schema Migration (compilation, ~Varies by database size and complexity) — Application startup blocked until database schema changes complete, ensuring consistency
- GraphQL Schema Generation (compilation, ~Proportional to number of collections and fields) — GraphQL endpoints unavailable until schema generation completes during initialization
Control Points
- Database Adapter Selection (architecture-switch) — Controls: Switches between MongoDB, PostgreSQL, SQLite implementations with different query capabilities and performance characteristics
- Access Control Strategy (feature-flag) — Controls: Enables/disables CRUD operations based on user roles, authentication status, and custom functions
- Upload Storage Provider (architecture-switch) — Controls: Routes file uploads to local filesystem, S3, GCS, or other cloud storage providers
- Rich Text Editor (architecture-switch) — Controls: Switches between Lexical, Slate, or custom rich text implementations for content editing
- Authentication Strategy (feature-flag) — Controls: Enables local auth, OAuth providers, custom auth strategies, and session management approaches
Technology Stack
Provides type safety across the entire system, from configuration validation to API response typing and database schema generation
Powers the admin UI as a React application and provides the integration layer for embedding Payload in existing Next.js projects
Renders the admin interface components, forms, tables, and dashboard elements with dynamic UI generation from configurations
Provides SQL database abstraction, query building, schema management, and migrations for PostgreSQL and SQLite adapters
Handles MongoDB operations, schema validation, and document modeling for the MongoDB database adapter
Auto-generates GraphQL schemas and resolvers from Payload configurations, enabling GraphQL API access to collections
Provides rich text editing capabilities through Meta's extensible rich text framework for content fields
Handles transactional email delivery for authentication workflows and user notifications through various SMTP providers
Manages the monorepo build system, coordinating package builds, caching, and dependency management across 132 packages
Provides test runner and assertion framework for unit and integration testing across all packages in the monorepo
Key Components
- Payload (orchestrator) — Central orchestrator that initializes database connections, registers collections and globals, sets up authentication, and coordinates all system components based on configuration
packages/payload/src/index.ts - DatabaseAdapter (adapter) — Abstract database interface that translates Payload's generic CRUD operations into database-specific queries, handling transactions, migrations, and schema management
packages/drizzle/src/index.ts - CollectionRouter (gateway) — HTTP request handler that parses REST API requests, applies access control, executes CRUD operations through database adapter, and formats responses
packages/payload/src/collections/requestHandlers/index.ts - AuthStrategy (processor) — Handles user authentication, session management, password hashing, and JWT token generation/validation across different auth strategies
packages/payload/src/auth/index.ts - SchemaGenerator (transformer) — Transforms Payload field configurations into database-specific table schemas, handling relationships, indexes, and constraints
packages/drizzle/src/schema/index.ts - AdminUI (gateway) — React-based admin interface that dynamically renders forms, tables, and dashboards based on collection configurations, handling user interactions and API calls
packages/ui/src/index.ts - HookRunner (dispatcher) — Executes user-defined lifecycle hooks (beforeCreate, afterRead, etc.) at specific operation points, allowing custom business logic injection
packages/payload/src/collections/operations/hooks/index.ts - StorageAdapter (adapter) — Handles file uploads, storage, and retrieval through pluggable providers (S3, GCS, local), managing file metadata and serving URLs
packages/storage-s3/src/index.ts - GraphQLGenerator (transformer) — Automatically generates GraphQL schema, types, and resolvers from Payload collection configurations, enabling GraphQL API access
packages/graphql/src/index.ts - EmailAdapter (adapter) — Sends transactional emails through configurable providers (Nodemailer, Resend) for auth workflows, notifications, and user communications
packages/email-nodemailer/src/index.ts
Package Structure
The core CMS engine providing collections, fields, authentication, hooks, and the configuration system that orchestrates all other components.
Next.js integration layer that embeds Payload admin UI and API routes into existing Next.js applications.
React component library providing the admin interface components, forms, tables, and dashboard elements.
CLI tool for scaffolding new Payload projects from templates with database setup and configuration.
TypeScript client SDK for making type-safe API calls to Payload backends from frontend applications.
Generates GraphQL schema and resolvers from Payload collection configurations for GraphQL API access.
Database abstraction layer providing CRUD operations, migrations, and query building for SQL databases.
MongoDB adapter implementing Payload's database interface using Mongoose for document operations.
PostgreSQL adapter using Drizzle ORM to implement Payload's database operations for relational data.
Rich text editor integration using Meta's Lexical framework for structured content editing.
File storage adapter for Amazon S3 and S3-compatible services handling uploads and media management.
E-commerce plugin adding product catalogs, shopping cart functionality, and order management collections.
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaCompare payload
Related Fullstack Repositories
Frequently Asked Questions
What is payload used for?
Builds TypeScript fullstack applications with instant backend APIs and admin panels using Next.js payloadcms/payload is a 10-component fullstack written in TypeScript. Data flows through 7 distinct pipeline stages. The codebase contains 6311 files.
How is payload architected?
payload is organized into 6 architecture layers: Configuration & Core, Database Adapters, API & Integration, UI & Admin, and 2 more. Data flows through 7 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.
How does data flow through payload?
Data moves through 7 stages: Load Configuration → Generate Database Schema → Process API Request → Execute Database Operation → Run Lifecycle Hooks → .... Data flows through Payload in multiple patterns: Configuration-driven setup loads user configs and generates database schemas and API routes. Request processing parses incoming HTTP/GraphQL requests, applies access control and validation, executes database operations through adapters, runs hooks, and returns formatted responses. Content creation flows from admin UI forms through validation, hooks, storage adapters for files, and database persistence. The system maintains type safety throughout by generating TypeScript types from configurations. This pipeline design reflects a complex multi-stage processing system.
What technologies does payload use?
The core stack includes TypeScript (Provides type safety across the entire system, from configuration validation to API response typing and database schema generation), Next.js (Powers the admin UI as a React application and provides the integration layer for embedding Payload in existing Next.js projects), React (Renders the admin interface components, forms, tables, and dashboard elements with dynamic UI generation from configurations), Drizzle ORM (Provides SQL database abstraction, query building, schema management, and migrations for PostgreSQL and SQLite adapters), Mongoose (Handles MongoDB operations, schema validation, and document modeling for the MongoDB database adapter), GraphQL (Auto-generates GraphQL schemas and resolvers from Payload configurations, enabling GraphQL API access to collections), and 4 more. This broad technology surface reflects a mature project with many integration points.
What system dynamics does payload have?
payload exhibits 4 data pools (Database Collections, Configuration Registry), 4 feedback loops, 5 control points, 4 delays. The feedback loops handle polling and recursive. These runtime behaviors shape how the system responds to load, failures, and configuration changes.
What design patterns does payload use?
5 design patterns detected: Adapter Pattern, Plugin Architecture, Configuration-Driven Development, Hook System, Monorepo Package Architecture.
How does payload compare to alternatives?
CodeSea has side-by-side architecture comparisons of payload with strapi, directus. These comparisons show tech stack differences, pipeline design, system behavior, and code patterns. See the comparison pages above for detailed analysis.
Analyzed on April 20, 2026 by CodeSea. Written by Karolina Sarna.