当你超越 Strapi CMS:使用 Payload + Supabase 构建
当你的Strapi不够用时:使用Payload + Supabase构建
在过去几年里,我为十多个客户项目设置了Strapi。这是一个很好的CMS入门工具——友好的管理面板、不错的插件生态系统、完整的文档。但在大约18个月的某个时刻,我合作过的几乎每个团队都会遇到瓶颈。数据迁移变得痛苦,自定义功能感觉很hacky,你那些热爱TypeScript的前端开发人员开始抱怨开发体验。如果这听起来很熟悉,你不是一个人。让我带你了解你已经超越Strapi的迹象,更重要的是,该如何重新构建。

目录
- 蜜月期:为什么Strapi初期有效
- 你已超越Strapi的六个信号
- 了解你的选项:Payload vs Supabase vs 坚持现状
- 为什么Payload CMS是自然的下一步
- Supabase的适用范围(以及不适用的地方)
- Payload + Supabase堆栈:架构深度探讨
- 迁移策略:离开Strapi而不失去理智
- 性能基准和真实数据
- 这个堆栈不合适的场景
- 常见问题
蜜月期:为什么Strapi初期有效
让我们公正对待Strapi。它有6.5万多个GitHub星标是有原因的。当你在启动一个新的内容驱动项目时,内容类型构建器确实很有用。你在GUI中点击,定义一些字段,然后——你就有了REST和GraphQL API。非技术性的内容编辑可以登录管理面板并在一小时内开始发布内容。
对于早期初创公司、营销网站和博客,Strapi是完全合理的选择。它支持PostgreSQL、MySQL、MariaDB和SQLite。插件市场有超过100个社区扩展。社区版在MIT许可证下免费。
我多次推荐过Strapi。我不是来贬低它的。我是来讨论接下来会发生什么。
你已超越Strapi的六个信号
这些是我反复看到的模式。如果其中三个或更多引起共鸣,是时候开始规划迁移了。
1. 数据迁移让你紧张
v4到v5的升级是破坏许多团队的那个。Strapi记录了50多个破坏性变更。在实践中,我看到中等复杂度项目的迁移耗费40多小时的开发者时间。这不是小版本更新——这是对你内容层的重写。
如果你因为知道会破坏一半的自定义控制器而对下一个主要版本感到害怕,你已经超越了这个工具。
2. 你的开发人员在与框架对抗
Strapi的内容类型构建器对于非技术用户来说很棒。对于喜欢TypeScript并想要代码优先模式的开发人员来说,这是一个瓶颈。GUI生成你不应该编辑的文件。生命周期钩子感觉像是硬加上去的。TypeScript支持在v4后期才添加,仍然不是原生的——更像是事后考虑。
当你的团队开始为框架构建变通方法而不是用它来构建功能时,这是一个明确的信号。
3. 性能成为了一个问题
Strapi的冷启动通常在500ms到2000ms之间。没有激进缓存的全局延迟在200-500ms之间。对于博客来说,这很好。对于跨多个地区为用户提供服务的电子商务平台,这不够。
我有一个客户在Strapi上运行多语言产品目录。一旦他们的内容条目超过约50,000条且有深层关系,API响应时间就超过了2秒的标记。再多的索引也无法解决。
4. 你需要的功能被锁定在付费层后面
Strapi的增长计划运行$45/月,包括3个座位(额外座位$15/座位)。这解锁了AI功能、实时预览和内容历史。企业定价是自定义的。
问题不在价格——问题在原则。实时预览和内容版本控制等功能在2025年的CMS中感觉像是基本配置。在开源工具上将它们锁定在订阅后面会让开发团队感到反感。
5. 你的堆栈已经超越了Strapi的架构
如果你全身心投入到Next.js、Vercel和TypeScript,Strapi开始感觉像是一个尴尬的附属物。它作为一个单独的Node.js服务运行。这意味着单独的部署、单独的监控、单独的扩展问题。你的前端团队在几秒内部署到Vercel,而你的CMS需要自己的基础设施。
6. 自定义扩展感觉像是手术
想添加条件字段逻辑?带验证的嵌套可重复块?自定义管理面板组件?在Strapi中,这些都是可能的,但很痛苦。管理面板是一个React应用,但扩展它意味着导航一个不像普通React开发的专有扩展系统。

了解你的选项:Payload vs Supabase vs 坚持现状
在我们进一步之前,让我们明确这些工具实际上是什么,因为我看到它们经常被混淆。
| 工具 | 实际上是什么 | 最适合 | 不太适合 |
|---|---|---|---|
| Strapi | 带有管理GUI的开源无头CMS | 内容编辑、快速API生成 | 代码优先团队、高性能应用 |
| Payload CMS | 在Next.js内运行的代码优先CMS框架 | TypeScript开发者、自定义内容应用 | 非技术独立运营者 |
| Supabase | 开源后端平台(DB、认证、存储、实时) | 应用数据、认证、文件存储 | 内容编辑工作流 |
| Directus | SQL优先无头CMS,带自动生成的API | 拥有现有数据库的团队 | 深度Next.js集成 |
| Sanity | 带实时协作的托管无头CMS | 编辑团队、结构化内容 | 预算紧张的自托管用户 |
Payload和Supabase不是竞争对手——它们是互补的。Payload处理你的内容建模、管理UI和内容API。Supabase处理你的数据库托管、认证、文件存储和实时订阅。它们一起替代Strapi,而且还能做更多。
为什么Payload CMS是自然的下一步
Payload在2025年及以后取得了重大进展。MG Software称其为TypeScript/Next.js集成的"市场颠覆者",我认为这是准确的。
基础架构差异是这样的:Payload在你的Next.js应用内运行。不是并排运行。不是作为一个单独的服务。在内部。你的CMS和前端共享相同的部署、相同的TypeScript类型、相同的构建过程。
代码优先模式定义
与其在GUI中点击来创建内容类型,你写TypeScript:
import { CollectionConfig } from 'payload';
export const Products: CollectionConfig = {
slug: 'products',
admin: {
useAsTitle: 'name',
defaultColumns: ['name', 'price', 'status'],
},
access: {
read: () => true,
create: ({ req: { user } }) => user?.role === 'admin',
},
fields: [
{
name: 'name',
type: 'text',
required: true,
},
{
name: 'price',
type: 'number',
min: 0,
},
{
name: 'description',
type: 'richText',
},
{
name: 'category',
type: 'relationship',
relationTo: 'categories',
hasMany: false,
},
{
name: 'variants',
type: 'array',
fields: [
{ name: 'sku', type: 'text', required: true },
{ name: 'color', type: 'select', options: ['red', 'blue', 'green'] },
{
name: 'stock',
type: 'number',
admin: {
condition: (data, siblingData) => siblingData?.sku !== undefined,
},
},
],
},
],
hooks: {
afterChange: [
async ({ doc, operation }) => {
if (operation === 'update' && doc.stock === 0) {
// 触发补货通知
}
},
],
},
};
这是一个真实的内容类型,具有条件字段逻辑、嵌套数组、关系字段、基于角色的访问控制和生命周期钩子。全部在一个文件中。全部类型安全。全部在Git中版本控制。
尝试在Strapi中完成这个操作而不接触三个不同的文件和管理扩展系统。
三个API层
Payload从你的模式自动生成REST和GraphQL API。但杀手级功能是本地API——直接数据库查询从你的服务器端代码,零HTTP开销:
// 在一个Next.js服务器组件内部
import { getPayload } from 'payload';
import config from '@payload-config';
export default async function ProductPage({ params }) {
const payload = await getPayload({ config });
const product = await payload.findByID({
collection: 'products',
id: params.id,
depth: 2, // 填充深度为2级的关系
});
return <ProductDetail product={product} />;
}
没有fetch调用。没有API路由。没有序列化开销。这就是为什么Payload在可比设置中的内容检索速度大约是Strapi的7倍。
Supabase的适用范围(以及不适用的地方)
Supabase不是一个CMS。我想对此非常清楚。它是一个建立在PostgreSQL上的后端平台。但它解决了Strapi处理不好且Payload根本不处理的几个问题。
Supabase为堆栈带来了什么
- 托管PostgreSQL:Payload的PostgreSQL适配器直接连接到Supabase数据库。你可以获得连接池、自动备份和直接SQL查询的仪表板。Pro计划的价格从$25/月开始,根据使用情况扩展。
- 认证:Supabase Auth支持电子邮件/密码、魔术链接、OAuth提供商和行级安全。如果你的应用在CMS管理之外有用户端功能,这是巨大的。
- 文件存储:S3兼容的对象存储,带CDN。Payload可以处理媒体上传,但Supabase存储处理应用文件、用户上传以及CMS上下文之外的任何内容。
- 实时订阅:PostgreSQL的LISTEN/NOTIFY被包装在一个干净的WebSocket API中。将这与Payload的实时预览配对,以获得实时内容编辑体验。
- 边缘函数:基于Deno的无服务器函数,用于webhook处理程序、后台作业和集成。
Supabase不做什么
它不为内容编辑提供管理面板。它不生成具有富文本字段和媒体管理的内容API。它不处理内容本地化或版本历史。那是Payload的工作。
Payload + Supabase堆栈:架构深度探讨
这是我为离开Strapi迁移的团队设置的方式。这是我们通常为Next.js开发项目推荐的架构,其中内容管理是核心需求。
项目结构
├── src/
│ ├── app/ # Next.js应用路由器
│ │ ├── (frontend)/ # 面向公众的页面
│ │ └── (payload)/ # CMS管理路由(自动生成)
│ ├── collections/ # Payload集合配置
│ │ ├── Posts.ts
│ │ ├── Products.ts
│ │ └── Users.ts
│ ├── globals/ # Payload全局配置
│ │ └── SiteSettings.ts
│ ├── lib/
│ │ └── supabase.ts # Supabase客户端初始化
│ └── payload.config.ts # 主Payload配置
├── supabase/
│ └── migrations/ # Supabase数据库迁移
├── .env.local
└── package.json
将Payload连接到Supabase PostgreSQL
// payload.config.ts
import { buildConfig } from 'payload';
import { postgresAdapter } from '@payloadcms/db-postgres';
import { lexicalEditor } from '@payloadcms/richtext-lexical';
import { Posts } from './collections/Posts';
import { Products } from './collections/Products';
export default buildConfig({
db: postgresAdapter({
pool: {
connectionString: process.env.SUPABASE_DB_URL,
// 对于无服务器,使用Supabase的连接池化器
max: 10,
},
}),
editor: lexicalEditor(),
collections: [Posts, Products],
secret: process.env.PAYLOAD_SECRET,
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},
});
一个重要的注意事项:部署到像Vercel这样的无服务器环境时,使用Supabase的连接池化器URL(端口6543),而不是直接连接URL。直接连接对本地开发很有效。
为应用用户添加Supabase认证
Payload处理CMS管理认证。Supabase处理其他所有内容:
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// 在服务器组件或API路由中
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export async function getServerSupabase() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
);
},
},
}
);
}
这种分离很干净:Payload拥有内容。Supabase拥有应用数据和用户身份。它们共享相同的PostgreSQL实例,但保持各自的职能。
迁移策略:离开Strapi而不失去理智
我不会美化这个——迁移需要工作。但它的痛苦程度远低于Strapi v4到v5的升级,因为你要迁移到的系统尊重你现有的思维方式。
分步走方法
- **审核你的Strapi内容类型。**从内容类型构建器以JSON格式导出它们。将每个映射到Payload集合配置。
- **在新的Next.js项目中设置Payload。**运行
npx create-payload-app@latest并选择PostgreSQL适配器。 - **将Payload指向你的Supabase数据库。**创建一个新的Supabase项目,获取连接字符串,配置适配器。
- **在TypeScript中重新创建模式。**这是工作量最大的部分。每个Strapi内容类型变成一个Payload集合。字段映射几乎一对一——文本、数字、富文本、关系、媒体。
- **从Strapi导出数据。**如果你使用了PostgreSQL,使用
pg_dump,或者编写一个针对Strapi REST API的脚本来拉取所有内容。 - **导入到Payload。**在seed脚本中使用Payload的本地API来批量创建内容。
- **更新你的前端。**将Strapi API调用交换为Payload本地API调用(在服务器组件中)或REST/GraphQL调用(在客户端组件中)。
- **部署。**由于Payload在Next.js内运行,你部署一个应用程序而不是两个。
对于复杂的迁移,我们的无头CMS开发团队可以帮助规划过渡。我们做过足够多次这个,知道地雷在哪里。
性能基准和真实数据
这些是重要的数字,从2025年发布的基准和我们自己的测试收集:
| 指标 | Strapi v5 | Payload 3.x | Payload + Supabase |
|---|---|---|---|
| 冷启动时间 | 500-2000ms | 100-300ms | 150-350ms |
| 简单查询(单项) | 45-80ms | 8-15ms | 10-20ms |
| 复杂查询(填充、3级) | 200-500ms | 30-80ms | 40-100ms |
| 管理面板加载 | 2-4s | 1-2s | 1-2s |
| 构建时间(500页、ISR) | N/A(分离) | 45-90s | 50-100s |
| 全球延迟(无CDN) | 200-500ms | 50-150ms | 60-160ms |
Supabase连接池化器与直接PostgreSQL连接相比增加了较小的开销,通常为5-15ms。这在实际应用中可以忽略不计。
一个警告:Payload的填充字段查询(深层关系解析)已被标记为比原始数据库查询更慢——根据GitHub问题#11325,大约比直接Mongoose/Drizzle调用慢15倍。对于读取密集型页面,我建议使用Next.js ISR或缓存填充结果,而不是每次请求都查询数据库。
这个堆栈不合适的场景
如果我没有提及Payload + Supabase过度设计或完全错误的场景,我就对你做了伤害。
- **你的团队不写TypeScript。**Payload是代码优先。如果你的内容团队管理所有内容,你没有维护CMS的开发人员,Strapi的GUI确实更好。或者看看Sanity或Contentful。
- **你今天需要一个大型插件生态系统。**Payload的生态系统在增长,但比Strapi的100多个扩展要小。如果你需要一个特定的集成作为Strapi插件存在但Payload不存在,请计入构建时间。
- **你在构建一个简单的博客或营销网站。**Strapi对此很好。Astro与无头CMS也很好。不要过度设计。
- **你需要边缘优先性能。**如果sub-50ms全球延迟是硬性需求,看看SonicJS在Cloudflare Workers上。Payload运行在Node.js上——它很快,但不是边缘原生。
想讨论这个迁移是否对你的特定项目有意义?联系我们——我们会给你一个诚实的评估,而不是推销话术。
常见问题
Payload CMS真的免费吗? 是的。Payload在MIT许可证下是免费的,可以自托管,没有功能限制。有一个可选的Payload Cloud托管服务供不想管理基础设施的团队使用,但所有CMS功能——实时预览、访问控制、本地化、版本控制——在开源版本中可用。将其与Strapi相比较,后者在$45/月的增长计划后面有实时预览和内容历史。
我能单独使用Supabase作为CMS吗? 在技术上,你可以使用Supabase的自动生成的API和行级安全在Supabase之上构建内容管理界面。但你会重新构建Payload开箱即用提供的功能:管理面板、富文本编辑、媒体管理、内容版本控制和访问控制。Supabase是一个后端平台,而不是CMS。将其用于它擅长的——数据库托管、认证、存储——并让Payload处理内容层。
从Strapi迁移到Payload需要多长时间? 对于一个典型的项目,有10-20个内容类型和数千条条目,预计2-4周的开发者时间。模式重新创建是最大的部分——将Strapi内容类型翻译为Payload TypeScript配置。数据迁移通常用一个好的脚本就能在一两天内完成。前端更新取决于你的代码与Strapi API响应格式的耦合程度。使用数据访问层或抽象的团队会更容易。
Payload支持除PostgreSQL外的其他数据库吗? Payload通过官方数据库适配器支持MongoDB和PostgreSQL。对于本文描述的Supabase堆栈,你会使用PostgreSQL适配器。如果你来自MongoDB背景,Payload的MongoDB适配器实际上更成熟,因为MongoDB是Payload原来的数据库。在2025年,两者都是生产就绪的。
Directus作为Strapi的替代品怎么样? Directus是一个不错的选项,特别是如果你有一个你想通过CMS界面公开的现有SQL数据库。它从你的数据库模式自动生成管理面板和API,这很聪明。与Payload相比的主要缺点是缺乏深度Next.js集成——Directus作为一个单独的服务运行,类似于Strapi。如果你的团队不在Next.js/Vercel堆栈上,Directus值得认真考虑。
我能在Vercel上部署Payload + Supabase吗? 绝对可以——这实际上是理想的部署目标。由于Payload在你的Next.js应用内运行,部署到Vercel就像推送到你的Git仓库一样简单。Supabase作为托管服务运行,所以那一侧没有什么要部署的。你的总基础设施变成:用于计算和CDN的Vercel,用于数据库和认证的Supabase。两个服务,一个部署管道。我们经常通过我们的Next.js开发实践为客户设置这个。
Payload管理面板是可定制的吗? 非常可以。管理UI是用React构建的,支持自定义组件、自定义视图和自定义字段。你可以添加仪表板小部件、创建自定义导航项目,并覆盖任何默认UI元素。自Payload 3.x以来,管理定制使用React服务器组件,这意味着你的自定义管理代码可以在服务器端获取数据,无需API调用。这与Strapi的管理扩展系统不同,后者需要弹出和打补丁。
在生产中运行这个堆栈的成本是多少? 对于一个小到中等的项目:Vercel Pro $20/月 + Supabase Pro $25/月 = $45/月总计。这为你提供无服务器计算、带有8GB存储的托管PostgreSQL数据库、250MB文件存储、50,000个月活跃认证用户和自动备份。从那里根据需要扩展。将其与在VPS上自托管Strapi($20-50/月)加上管理自己的数据库进行比较,或Strapi Cloud的增长计划$45/月,座位数有限。Payload + Supabase组合成本有竞争力,并且易于操作得多。有关详细的项目估算,请查看我们的定价页面。