Payload CMS vs Directus 2026:代码优先还是数据库优先?
你的 Next.js 构建将在周五启动。客户希望拥有完整的编辑控制权,数据库必须本地托管,而你的首席开发拒绝使用任何没有 TypeScript 自动补全的东西。你已排除了专有的 SaaS 平台,并将目光锁定在两个开源无头 CMS 竞争者上:Payload CMS 和 Directus。两者都运行在 Node.js 上。两者都启动快速。两者都支持自托管。但其中一个要求你在数据库存在之前在代码中定义模式。另一个读取现有数据库并围绕其构建管理 UI。这个单一的分岔点——代码优先 vs 数据库优先——将决定你的模式是否生活在版本控制中或通过 UI 点击生成,你的类型是否自动流向前端或需要手动同步步骤,以及你的部署是感觉像推送 Git 提交还是迁移生产表。那么哪种哲学适合你的团队实际工作方式?
过去两年我用两者都发布了生产网站。这是我真实的想法,不是营销页面说的。
目录
- 核心哲学分歧
- 模式设计:代码优先 vs 数据库优先
- TypeScript 和开发者体验
- API 层和查询能力
- 管理面板和内容编辑
- 身份验证和访问控制
- 性能和可扩展性
- 部署和托管
- 2026 年的定价和许可
- 何时选择哪个
- 常见问题

核心哲学分歧
让我直言不讳地说这一点,因为这是最重要的一件事:
Payload CMS 是代码优先的。 你在 TypeScript 配置文件中定义你的模式。数据库符合你的代码。
Directus 是数据库优先的。 你可以指向现有数据库,它会对模式进行自省。管理 UI 符合你的数据库。
没有哪种方法在客观上更好。但其中一种将对 你的项目 戏剧性地更好,在这一点上出错意味着以后会有痛楚。
如果你是一名开发人员构建全新项目,并且希望你的 CMS 模式与应用程序代码一起受版本控制,Payload 会感觉像家一样。如果你有一个现有的 PostgreSQL 数据库,有 200 个表,你需要在其上面添加内容管理层,Directus 将为你节省数周。
模式设计:代码优先 vs 数据库优先
Payload 的代码优先方法
在 Payload 3.x(截至 2026 年的当前主要版本)中,你在 TypeScript 配置文件中定义集合:
// collections/Posts.ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
name: 'content',
type: 'richText',
},
{
name: 'author',
type: 'relationship',
relationTo: 'users',
},
{
name: 'publishedAt',
type: 'date',
},
{
name: 'status',
type: 'select',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
],
defaultValue: 'draft',
},
],
}
这个配置 是 你的真实来源。当 Payload 启动时,它自动生成数据库迁移(Payload 3.x 在底层使用 Drizzle ORM,支持 PostgreSQL 或 SQLite,仍然支持 MongoDB)。你的模式在 Git 中。你在 PR 中审查模式更改。这和你用于应用程序代码的工作流程一样,这就是重点。
Payload 也从这些配置自动生成 TypeScript 类型。因此,当你在 Next.js 前端中查询 posts 时,你会获得完整的类型安全性,无需维护单独的类型定义。
Directus 的数据库优先方法
Directus 采取相反的立场。你可以:
- 指向 Directus 一个现有数据库,它读取模式
- 通过管理 UI 创建集合,生成 SQL 迁移
- 使用 Directus SDK 以编程方式管理模式
// 通过 Directus SDK 创建集合
import { createDirectus, rest, createCollection } from '@directus/sdk'
const client = createDirectus('http://localhost:8055').with(rest())
await client.request(
createCollection({
collection: 'posts',
schema: {
name: 'posts',
},
meta: {
icon: 'article',
note: 'Blog posts',
},
})
)
Directus 11(发布于 2025 年末)显著改进了模式迁移工具。你现在可以将模式快照导出和导入为 YAML 文件,这使得版本控制比以前更实用:
# 导出当前模式
npx directus schema snapshot ./schema-snapshot.yaml
# 将模式差异应用于另一个环境
npx directus schema apply ./schema-snapshot.yaml
但这是老实话:即使有这些改进,Directus 模式管理在 Git 工作流中的感觉也不如 Payload 的方法自然。你是在快照状态而不是声明意图。
模式对比表
| 方面 | Payload CMS | Directus |
|---|---|---|
| 模式真实来源 | TypeScript 配置文件 | 数据库本身 |
| 模式版本控制 | 原生 Git 工作流 | YAML 快照(在 v11 中改进) |
| 现有数据库支持 | 有限(迁移路径) | 优秀(自省) |
| 自动生成的类型 | 是,来自配置 | 是,通过 SDK + CLI |
| 数据库支持 | PostgreSQL、SQLite、MongoDB | PostgreSQL、MySQL、MariaDB、SQLite、MS SQL、CockroachDB、OracleDB |
| ORM / 查询层 | Drizzle ORM(v3) | 自定义查询引擎(基于 Knex) |
| 迁移生成 | 从配置更改自动生成 | 模式差异快照 |
TypeScript 和开发者体验
Payload 的 TypeScript 故事
Payload 是完全的 TypeScript。整个项目用 TypeScript 编写,用 TypeScript 配置,并生成 TypeScript。当你运行 payload generate:types 时,你会得到每个集合的接口:
// 自动生成
export interface Post {
id: string
title: string
content?: RichTextContent
author?: string | User
publishedAt?: string
status?: 'draft' | 'published'
createdAt: string
updatedAt: string
}
这些类型流向你的本地 API、REST API 响应和 GraphQL 查询。在 Payload 3.x 中,由于它运行 在你的 Next.js 应用内 ,你可以直接导入和使用这些类型。不需要单独的 SDK。没有用于服务器端渲染的 API 调用——你直接查询数据库:
// 在 Next.js 服务器组件中
import { getPayload } from 'payload'
import config from '@payload-config'
export default async function BlogPage() {
const payload = await getPayload({ config })
const posts = await payload.find({
collection: 'posts',
where: {
status: { equals: 'published' },
},
})
// posts.docs 完全类型化为 Post[]
return <PostList posts={posts.docs} />
}
这真的是非常好的开发体验。没有网络跳转,完整的类型,它就是... 函数。
Directus 的 TypeScript 故事
Directus 显著改进了其 TypeScript 支持。@directus/sdk 包支持通用类型参数:
import { createDirectus, rest, readItems } from '@directus/sdk'
interface Schema {
posts: Post[]
users: User[]
}
interface Post {
id: number
title: string
content: string
author: number | User
published_at: string
status: 'draft' | 'published'
}
const client = createDirectus<Schema>('http://localhost:8055').with(rest())
const posts = await client.request(
readItems('posts', {
filter: { status: { _eq: 'published' } },
fields: ['id', 'title', 'content', 'author.*'],
})
)
缺点?你必须自己编写和维护那些类型定义(或使用社区工具如 directus-typescript-gen 生成它们)。类型不是以 Payload 那样的相同第一类方式从模式自动派生的。这是数据库优先的权衡:数据库不了解 TypeScript。

API 层和查询能力
两者都生成 REST 和 GraphQL API,但风味不同。
Payload 提供:
- 具有深度控制的 REST API 用于关系
- GraphQL API(从你的配置自动生成)
- 本地 API(直接数据库查询,无 HTTP 开销)
- 完整的查询运算符:equals、not_equals、greater_than、in、contains 等
Directus 提供:
- 具有细粒度字段选择的 REST API
- GraphQL API(从模式自省自动生成)
- Directus SDK(包装 REST,如果你提供接口则有类型)
- 丰富的过滤,包含
_eq、_neq、_gt、_in、_contains、逻辑_and/_or运算符 - 聚合查询内置于 API(计数、求和、平均等)
Directus 在 API 灵活性方面对复杂查询有轻微优势,特别是聚合。如果你需要通过 API 进行 GROUP BY 风格的查询,Directus 原生处理。对于 Payload,你通常会下降到 Drizzle ORM 层或编写自定义端点。
Payload 的杀手级优势是本地 API。当你的 CMS 和 Next.js 前端在同一个进程中时,你完全跳过 HTTP。对于服务器渲染的页面,这意味着更快的构建和更低的延迟。
管理面板和内容编辑
Payload 3.x 的管理面板是用 React 构建的,作为你的 Next.js 应用程序的一部分发布。它可以用 React 组件定制——你可以覆盖几乎 UI 的任何部分。基于块的富文本编辑器(从 v3 开始基于 Lexical)功能强大且可扩展。
Directus 的管理面板是独立的 Vue.js 应用程序(Directus 数据工作室)。它经过精心设计,视觉设计强大,非技术用户倾向于快速学习。Directus 中的流/自动化构建器在视觉上和易用性上明显比 Payload 的钩子系统更强。
| 功能 | Payload CMS | Directus |
|---|---|---|
| 管理框架 | React(Next.js) | Vue.js(独立) |
| 富文本编辑器 | 基于 Lexical | TipTap / WYSIWYG |
| 自定义字段 | React 组件 | Vue 扩展 |
| 工作流/自动化 | 钩子 + 自定义端点 | Directus 流(可视化构建器) |
| 本地化 | 内置字段级 i18n | 内置字段级 i18n |
| 内容版本控制 | 草稿/发布 + 版本 | 内容版本控制 + 修订 |
| 文件管理 | 内置媒体库 | 内置媒体库(带转换) |
这是我的老实话:对于开发者重型团队,Payload 的管理界面更自然地扩展,因为你在编写 React。对于内容编辑器是主要用户的团队,你希望低摩擦 UX,Directus 的管理面板开箱即用略微更易接近。
身份验证和访问控制
两个系统都有成熟的身份验证,但它们的工作方式不同。
Payload 使用基于集合的身份验证。你将一个集合标记为身份验证集合(通常 users),它会获得登录、注册、密码重置、电子邮件验证和基于 JWT/cookie 的会话。访问控制使用函数按集合和按字段定义:
{
slug: 'posts',
access: {
read: () => true, // 公共
create: ({ req: { user } }) => Boolean(user), // 已认证
update: ({ req: { user } }) => user?.role === 'admin',
delete: ({ req: { user } }) => user?.role === 'admin',
},
fields: [
{
name: 'internalNotes',
type: 'text',
access: {
read: ({ req: { user } }) => user?.role === 'admin',
},
},
],
}
这是 极其 强大的。访问控制函数接收完整的请求上下文,因此你可以实现任何模式——RBAC、ABAC、多租户、行级安全。
Directus 使用通过管理面板配置的基于角色的权限系统。你创建角色,分配细粒度权限(每个集合的 CRUDS),并添加带过滤器的自定义权限。它是视觉的和直观的,但对于不适合角色模型的复杂模式灵活性较低。
对于大多数项目,两者都足够。对于多租户 SaaS 或复杂的授权逻辑,Payload 的基于代码的访问控制无法超越。
性能和可扩展性
我在现实条件下用两者进行了负载测试。以下是我用 PostgreSQL 后端观察到的:
| 指标 | Payload CMS 3.x | Directus 11 |
|---|---|---|
| 简单读取(单个项目) | ~2-5ms 本地 API,~15-25ms REST | ~15-30ms REST |
| 列表查询(100 项,无关系) | ~8-15ms 本地 API,~30-50ms REST | ~25-50ms REST |
| 列表查询(100 项,2 级深) | ~20-40ms 本地 API,~60-100ms REST | ~50-120ms REST |
| 冷启动时间 | ~3-6s(Next.js 启动) | ~2-4s(独立) |
| 内存基线 | ~200-350MB(使用 Next.js) | ~150-250MB |
Payload 的本地 API 优势是真实的,对 SSR/SSG 工作负载意义重大。当你生成 10,000 个静态页面时,跳过每个查询的 HTTP 确实累加起来。
Directus 并不落后。它在高吞吐量 REST 工作负载中表现良好,其缓存层(Redis 支持)成熟。
部署和托管
Payload 3.x 是 Next.js 应用程序,这意味着你可以在 Next.js 运行的任何地方部署它:Vercel、Netlify、AWS、Docker 等。Payload Cloud(他们的托管服务)从 2026 年初的生产项目的 $30/月开始。
Directus 作为独立的 Node.js 应用程序运行。Docker 是推荐的部署方法。Directus Cloud 从 $29/月开始。自托管在 VPS 上很直接——它只是一个需要数据库连接的 Docker 容器。
一件值得注意的事:由于 Payload 3.x 就是 你的 Next.js 应用,你的 CMS 和前端一起部署。这简化了基础设施,但意味着你的 CMS 管理面板与你的前端一起扩展。对于高流量网站,前端和 CMS 有非常不同的扩展需求,你可能想考虑单独运行它们。
Directus 作为单独的服务,自然分离这些关注点。你的前端(无论是 Next.js、Astro 还是其他任何东西)通过 HTTP 连接到 Directus。这是更传统的无头架构。
在 Social Animal,我们为客户部署了两种架构。Payload-in-Next.js 方法对大多数营销网站和中等规模应用程序都很有效。对于具有多个前端消费者的企业设置,分离的 Directus 方法可能更清洁。
2026 年的定价和许可
| Payload CMS | Directus | |
|---|---|---|
| 许可证 | MIT | GPL-3.0(Cloud 功能使用 BSL) |
| 自托管成本 | 免费 | 免费 |
| Cloud 托管 | 起价 $30/月(Payload Cloud) | 起价 $29/月(Directus Cloud) |
| 企业层 | 自定义定价 | 自定义定价(起价约 $1,500/月) |
| 溢价功能 | 某些功能仅 Cloud | Directus+ 订阅($99/月用于市场扩展) |
两者都对自托管是真正的开源。Payload 的 MIT 许可证更宽容——你可以在商业产品中嵌入它,不受限制。Directus 的 GPL-3.0 许可证意味着衍生作品也必须是 GPL,这对 SaaS 产品可能很重要。
Directus 在 2025 年末推出了 Directus+,一项解锁高级市场扩展和优先支持的订阅。它是可选的,但一些更高级的扩展(如 AI 内容助手)在此付费墙后面。
何时选择哪个
选择 Payload CMS 何时:
- 你从零开始构建新项目(全新)
- 你的团队是 TypeScript 重型,想要模式即代码
- 你正在使用 Next.js,希望最紧密的集成
- 你需要复杂的、代码定义的访问控制
- 你想要一切都在可部署的单元中
- 你重视 MIT 许可证
选择 Directus 何时:
- 你有一个现有的数据库需要管理
- 你的团队包括需要修改模式的非开发人员
- 你需要从一个 CMS 支持多个前端(网络、移动、物联网)
- 你想要可视化的自动化/流构建器
- 你需要广泛的数据库支持(MySQL、MSSQL、Oracle 等)
- 你偏好 CMS 作为单独的、独立的服务
如果你正在为无头项目权衡这些选项,并想要第二意见,我们做 无头 CMS 架构咨询,可以在你在错误的那个三个月深入之前帮你选择正确的工具。
对于使用 Astro 作为前端框架的项目,Directus 的独立 API 方法自然配对,因为 Astro 在构建时或通过服务器端点获取数据。Payload 也工作,但你失去了本地 API 优势,因为 Astro 和 Payload 会是分离的进程。
常见问题
Payload CMS 在 2026 年真的是免费的吗? 是的。Payload CMS 是 MIT 许可的,完全免费自托管。Payload Cloud 是他们的付费托管服务,但 CMS 本身——包括所有核心功能——是开源的。在自托管版本上没有功能门槛。
Directus 可以在不修改现有数据库的情况下工作吗?
基本上是的。Directus 可以自省现有数据库并在其上创建管理层。它添加了一些系统表(前缀为 directus_)用于自己的配置,但它不会修改你的现有表。这是它最强的差异化因素之一。
哪一个对于单独的开发人员更好? Payload CMS 往往是在 TypeScript 中舒适的单独开发人员的最爱。代码优先的工作流意味着你可以快速设置集合,自动生成的类型减少了样板。如果你想要一个视觉界面来快速原型模式而不编写配置文件,Directus 更好。
我可以不使用 Next.js 来使用 Payload CMS 吗? 截至 Payload 3.x,Next.js 是主要适配器,管理面板在 Next.js 上运行。但是,REST 和 GraphQL API 与任何前端一起工作。你没有被锁定为你的消费者面向网站使用 Next.js——你只需要 Next.js 来运行 Payload 管理。关于额外适配器(如 Nuxt)有社区讨论,但官方没有任何东西。
Directus 如何处理内容本地化?
Directus 支持字段级翻译。你标记字段为可翻译的,配置你的语言,Directus 处理在相关表中存储翻译。API 允许你通过 ?fields 和语言参数请求特定语言的内容。它实现得很好,已经稳定多年。
哪一个有更好的插件/扩展支持? Directus 有更大的扩展市场,特别是 Directus+ 添加。你可以构建自定义接口、显示、端点、钩子和模块。Payload 的扩展模型基于 React 组件覆盖和插件——它很强大但生态系统较小。Payload 的插件往往更专注(SEO 插件、表单构建器、重定向),而 Directus 扩展涵盖更广泛的范围。
大型数据集的性能差异是否存在? 对于有数百万行的数据集,在适当索引时两者表现良好。Directus 在原始查询灵活性上有轻微优势,因为它从 API 查询生成 SQL 更直接。Payload 的 Drizzle ORM 层是有效的,但增加了小的抽象成本。在实践中,你的数据库调整重要程度远超过你选择哪个 CMS。两者都支持连接池,可以与读副本一起工作。
我以后可以从一个迁移到另一个吗? 你可以,但这并不简单。内容数据本身(存储在两者的 PostgreSQL 中)可以用标准数据库工具迁移。更难的部分是重新创建你的模式定义、访问控制规则和任何自定义逻辑。如果你为 无头架构 构建,保持你的前端与 CMS 特定 API 的解耦(使用抽象层)将使任何将来的 CMS 迁移显著更容易。