Розробка веб-сайту на Payload CMS
Payload CMS — headless CMS на Node.js з TypeScript-first підходом. Конфігурація — код, а не GUI: колекції, поля, хуки, контроль доступу описуються у TypeScript-файлах. Це означає type safety, рефакторинг через IDE, code review у git. База даних — MongoDB або PostgreSQL через Drizzle ORM. Admin panel генерується автоматично з конфігурації.
Архітектура проекту
Payload працює як монолит (CMS + frontend в одному Next.js додатку) або у режимі standalone API:
Монолит (рекомендовано):
├── app/ # Next.js App Router
│ ├── (frontend)/ # Публічні сторінки
│ └── (payload)/ # Admin panel: /admin
├── payload.config.ts # Конфігурація CMS
├── collections/ # Типи контенту
└── globals/ # Глобальні настройки
Створення проекту
npx create-payload-app@latest my-site
# Вибрати: template = website, database = PostgreSQL або MongoDB
cd my-site
npm install
npm run dev
# Admin: http://localhost:3000/admin
Колекції
Колекція — тип контенту з полями:
// collections/Posts.ts
import { CollectionConfig } from 'payload/types'
const Posts: CollectionConfig = {
slug: 'posts',
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'status', 'publishedAt'],
},
access: {
read: () => true,
create: ({ req }) => req.user?.role === 'admin',
update: ({ req }) => req.user?.role === 'admin',
},
fields: [
{ name: 'title', type: 'text', required: true },
{ name: 'slug', type: 'text', unique: true },
{ name: 'content', type: 'richText' },
{ name: 'status', type: 'select', options: ['draft', 'published'], defaultValue: 'draft' },
{ name: 'publishedAt', type: 'date' },
{ name: 'featuredImage', type: 'upload', relationTo: 'media' },
],
hooks: {
beforeChange: [
({ data }) => {
if (!data.slug && data.title) {
data.slug = data.title.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '')
}
return data
}
],
},
}
export default Posts
Рендеринг у Next.js
// app/(frontend)/[slug]/page.tsx
import { getPayloadHMR } from '@payloadcms/next/utilities'
import configPromise from '@payload-config'
import { notFound } from 'next/navigation'
export default async function Page({ params }: { params: { slug: string } }) {
const payload = await getPayloadHMR({ config: configPromise })
const result = await payload.find({
collection: 'pages',
where: { slug: { equals: params.slug }, status: { equals: 'published' } },
limit: 1,
})
const page = result.docs[0]
if (!page) notFound()
return (
<main>
<h1>{page.title}</h1>
<RichText content={page.content} />
</main>
)
}
Типовий tech stack
| Шар | Технологія |
|---|---|
| CMS + Admin | Payload CMS 2.x |
| Frontend | Next.js 14 App Router |
| База даних | PostgreSQL + Drizzle |
| Медіафайли | Cloudflare R2 / AWS S3 |
| Пошук | Payload built-in / Algolia |
| Resend / Nodemailer | |
| Деплой | Vercel / Railway |
Терміни
Базовий сайт з 3–5 типами контенту: 2–3 тижні. Складний проект з кастомними полями, i18n: 4–8 тижнів.







