你的 Next.js 构建将在周五启动。客户希望拥有完整的编辑控制权,数据库必须本地托管,而你的首席开发拒绝使用任何没有 TypeScript 自动补全的东西。你已排除了专有的 SaaS 平台,并将目光锁定在两个开源无头 CMS 竞争者上:Payload CMS 和 Directus。两者都运行在 Node.js 上。两者都启动快速。两者都支持自托管。但其中一个要求你在数据库存在之前在代码中定义模式。另一个读取现有数据库并围绕其构建管理 UI。这个单一的分岔点——代码优先 vs 数据库优先——将决定你的模式是否生活在版本控制中或通过 UI 点击生成,你的类型是否自动流向前端或需要手动同步步骤,以及你的部署是感觉像推送 Git 提交还是迁移生产表。那么哪种哲学适合你的团队实际工作方式?

过去两年我用两者都发布了生产网站。这是我真实的想法,不是营销页面说的。

目录

Payload CMS vs Directus 2026:代码优先 vs 数据库优先

核心哲学分歧

让我直言不讳地说这一点,因为这是最重要的一件事:

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 采取相反的立场。你可以:

  1. 指向 Directus 一个现有数据库,它读取模式
  2. 通过管理 UI 创建集合,生成 SQL 迁移
  3. 使用 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。

Payload CMS vs Directus 2026:代码优先 vs 数据库优先——架构

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 迁移显著更容易。