Payload CMS vs Directus 2026:代码优先 vs 数据库优先
2026年Payload CMS vs Directus:代码优先 vs 数据库优先
如果你在2026年构建一个无头CMS驱动的项目,并且已经将选择范围缩小到Payload CMS和Directus,恭喜——你的品味很不错。两者都是开源的、自托管的,并且基于Node.js构建。两者都有活跃的社区,并且正在快速推出功能。但它们对于内容模式应该如何出现代表了根本不同的哲学,这种差异将在你项目的每一个决定中产生涟漪效应。
在过去的两年里,我用两者都交付了生产网站。以下是我的真实想法,而不是营销页面说的内容。
目录
- 核心哲学分裂
- 模式设计:代码优先 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采取相反的立场。你可以:
- 指向一个现有的数据库,它读取模式
- 通过管理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
}
这些类型流向你的Local 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(从你的配置自动生成)
- Local 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中(count、sum、avg等)
Directus在API灵活性上略占上风,特别是复杂查询。如果你需要通过API做 GROUP BY 风格的查询,Directus原生处理。对于Payload,你通常会下降到Drizzle ORM层或编写自定义端点。
Payload的杀手锏优势是Local API。当你的CMS和你的Next.js前端是同一个进程时,你跳过HTTP。对于服务器渲染的页面,这意味着更快的构建和更低的延迟。
管理面板和内容编辑
Payload 3.x的管理面板是用React构建的,并作为你的Next.js应用程序的一部分发货。它可以通过React组件自定义——你可以覆盖几乎UI的任何部分。基于块的富文本编辑器(从v3开始基于Lexical)是强大的和可扩展的。
Directus的管理面板是一个独立的Vue.js应用程序(Directus Data Studio)。它经过抛光处理,有强大的视觉设计,非技术用户倾向于快速上手。Directus中的流程/自动化构建器比Payload的hooks系统明显更视觉和易于访问。
| 功能 | Payload CMS | Directus |
|---|---|---|
| 管理框架 | React(Next.js) | Vue.js(独立) |
| 富文本编辑器 | 基于Lexical | TipTap / WYSIWYG |
| 自定义字段 | React组件 | Vue扩展 |
| 工作流/自动化 | Hooks + 自定义端点 | Directus Flows(视觉构建器) |
| 本地化 | 内置字段级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 local API、~15-25ms REST | ~15-30ms REST |
| 列表查询(100项,无关系) | ~8-15ms local API、~30-50ms REST | ~25-50ms REST |
| 列表查询(100项,2级深) | ~20-40ms local API、~60-100ms REST | ~50-120ms REST |
| 冷启动时间 | ~3-6s(Next.js启动) | ~2-4s(独立) |
| 内存基线 | ~200-350MB(带Next.js) | ~150-250MB |
Payload的Local 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的多个前端(web、移动、IoT)
- 你需要一个视觉自动化/流构建器
- 你需要广泛的数据库支持(MySQL、MSSQL、Oracle等)
- 你更喜欢CMS作为一个单独的、独立的服务
如果你为无头项目权衡这些选项并想要第二意见,我们做无头CMS体系结构咨询,可以帮助你在错误的选择中花费三个月之前选择正确的工具。
对于使用Astro作为前端框架的项目,Directus的独立API方法自然配对,因为Astro在构建时或通过服务器端点获取数据。Payload也可以工作,但你失去了Local 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+添加。你可以构建自定义接口、显示、端点、hooks和模块。Payload的扩展模型基于React组件覆盖和插件——它很强大但生态更小。Payload的插件往往更专注(SEO插件、表单构建器、重定向)而Directus扩展涵盖更广泛的范围。
对于大型数据集有性能差异吗? 对于具有数百万行的数据集,两者在正确索引时都表现良好。Directus在原始查询灵活性上略占优势,因为它更直接地从API查询生成SQL。Payload的Drizzle ORM层很有效,但增加了一个小的抽象成本。在实践中,你的数据库调优重要性远高于你选择的CMS。两者都支持连接池,可以与读副本一起工作。
我能否稍后从一个迁移到另一个? 你可以,但这不是微不足道的。内容数据本身(对两者都存储在PostgreSQL中)可以用标准数据库工具迁移。更难的部分是重建你的模式定义、访问控制规则和任何自定义逻辑。如果你为无头架构构建,将你的前端与CMS特定的API分离(使用抽象层)将使任何未来的CMS迁移显著更容易。