TutorialEngineering
TypeScript Patterns for Payload CMS 3: Type Safety from Database to UI
Why TypeScript Matters
Payload CMS 3 is written in 100% TypeScript. Every field generates corresponding types, giving you compile-time safety from schema to component props.
Auto-Generated Types
Run npx payload generate:types to generate payload-types.ts:
1// Auto-generated from your collection configs2export interface Post {3 id: number4 title: string5 slug: string6 content: {7 root: { type: 'root'; children: SerializedEditorState[] }8 }9 heroImage?: number | Media10 authors?: (number | User)[]11 publishedAt?: string12 _status?: 'draft' | 'published'13 createdAt: string14 updatedAt: string15}Pattern 1: Typed Hooks
Collection Hooks
1import type { CollectionBeforeChangeHook } from 'payload'2 3export const generateSlug: CollectionBeforeChangeHook = async ({4 data,5 operation,6}) => {7 if (operation === 'create' && data.title && !data.slug) {8 data.slug = data.title9 .toLowerCase()10 .replace(/[^a-z0-9]+/g, '-')11 .replace(/(^-|-$)/g, '')12 }13 return data14}Pattern 2: Typed Access Control
1import type { Access } from 'payload'2 3// Only authors can update their own posts4export const isAuthorOrAdmin: Access = ({ req: { user } }) => {5 if (!user) return false6 if (user.role === 'admin') return true7 return { authors: { contains: user.id } }8}Pattern 3: Type-Safe Components
Import generated types in your React components. The compiler catches field mismatches:
1import type { Post } from '@/payload-types'2 3export const PostCard = ({ title, heroImage, publishedAt }: Post) => (4 <article>5 <h2>{title}</h2>6 {typeof heroImage === 'object' && (7 <img src={heroImage.url!} alt={heroImage.alt} />8 )}9 <time>{new Date(publishedAt!).toLocaleDateString()}</time>10 </article>11)Pattern 4: Typed API Responses
The Local API returns typed results. Use depth to control relationship population:
1// depth: 0 → heroImage is a number (ID)2// depth: 1 → heroImage is a Media object3// depth: 2 → heroImage.sizes populated4const post = await payload.findByID({5 collection: 'posts',6 id: 1,7 depth: 2,8})9// post.heroImage is now fully typed as MediaRelated Posts

TechnologyEngineering
1 min
Real benchmarks, D1 architecture, and a production deploymen…

Design
1 min
Spatial design, oklch() color systems, semantic motion, and …

Business
1 min
ROI analysis, migration strategy, and cost breakdown for ent…