當你已經超越 Strapi 時:使用 Payload + Supabase 構建

近幾年來,我已經為十幾個客戶專案設置過 Strapi。它是一個很棒的 CMS 入門工具——友善的管理面板、不錯的外掛生態系統、扎實的文檔。但在大約 18 個月的時候,我合作過的幾乎每一支團隊都撞上了一道牆。遷移變得痛苦,自訂義感覺很糟糕,你那些熱愛 TypeScript 的前端開發人員開始抱怨開發者體驗。如果這聽起來很熟悉,你不是孤單的。讓我帶你瞭解你已經超越 Strapi 的跡象,更重要的是,應該改為構建什麼。

當你已經超越 Strapi CMS 時:使用 Payload + Supabase 構建

目錄

蜜月期:為什麼 Strapi 初期運作良好

讓我們給予應有的讚譽。Strapi 之所以有 65,000+ 的 GitHub stars,是有原因的。當你正在啟動一個新的內容驅動專案時,內容類型建構器確實很有用。你點擊 GUI,定義一些欄位,繁榮——你已經有了 REST 和 GraphQL API。非技術內容編輯可以登入管理面板,在一小時內開始發佈。

對於早期創業公司、行銷網站和部落格,Strapi 是一個完全合理的選擇。它支援 PostgreSQL、MySQL、MariaDB 和 SQLite。外掛市場有超過 100 個社群擴充。社群版本在 MIT 許可證下免費。

我已經推薦過 Strapi 很多次。我不是來抨擊它的。我是來談談接下來會發生什麼的。

六個跡象表明你已經超越 Strapi

這些是我反覆看到的模式。如果其中三個或更多引起共鳴,是時候開始計劃遷移了。

1. 遷移使你感到緊張

v4 到 v5 的升級是破壞許多團隊的那個。Strapi 記錄了 50+ 個破壞性變更。在實踐中,我見過中等複雜度專案的遷移耗費 40+ 小時的開發人員時間。那不是次要版本 bump——那是內容層的重寫。

如果你對下一個主要版本感到害怕,因為你知道它會破壞你一半的自訂控制器,你已經超越這個工具了。

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 開發的專有擴充系統中導航。

當你已經超越 Strapi CMS 時:使用 Payload + Supabase 構建 - 架構

理解你的選項: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) {
          // Trigger restock notification
        }
      },
    ],
  },
};

那是一個真實的內容類型,具有條件欄位邏輯、嵌套陣列、關係欄位、基於角色的存取控制和生命週期掛鉤。全部在一個檔案中。全部類型安全。全部在 Git 中進行版本控制。

嘗試在 Strapi 中做到這一點,而不觸及三個不同的檔案和管理擴充系統。

三個 API 層

Payload 從你的架構自動生成 REST 和 GraphQL API。但殺手級功能是 Local API——直接資料庫查詢,來自伺服器端代碼,零 HTTP 開銷:

// Inside a Next.js Server Component
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, // Populate relationships 2 levels deep
  });
  
  return <ProductDetail product={product} />;
}

沒有提取呼叫。沒有 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 Storage 處理應用檔案、使用者上傳和 CMS 上下文之外的任何內容。
  • 即時訂閱:PostgreSQL 的 LISTEN/NOTIFY 包裝在乾淨的 WebSocket API 中。將其與 Payload 的即時預覽配對以獲得即時內容編輯體驗。
  • 邊界功能:基於 Deno 的無伺服器函式,用於 webhook 處理程式、後台工作和整合。

Supabase 不做的事情

它不會為內容編輯者提供管理面板。它不生成具有富文本欄位和媒體管理的內容 API。它不處理內容本地化或版本歷史。那是 Payload 的工作。

Payload + Supabase 堆疊:架構深度探討

這是我為遷移出 Strapi 的團隊設置此項的方式。這是我們通常為Next.js 開發專案推薦的架構,其中內容管理是核心要求。

專案結構

├── src/
│   ├── app/                    # Next.js App Router
│   │   ├── (frontend)/         # Public-facing pages
│   │   └── (payload)/          # CMS admin routes (auto-generated)
│   ├── collections/            # Payload collection configs
│   │   ├── Posts.ts
│   │   ├── Products.ts
│   │   └── Users.ts
│   ├── globals/                # Payload global configs
│   │   └── SiteSettings.ts
│   ├── lib/
│   │   └── supabase.ts         # Supabase client initialization
│   └── payload.config.ts       # Main Payload config
├── supabase/
│   └── migrations/             # Supabase DB migrations
├── .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,
      // Use Supabase's connection pooler for serverless
      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!
);

// In a Server Component or API route
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-to-v5 升級痛苦得多,因為你正在遷移到一個尊重你現有心智模型的系統。

逐步方法

  1. 審計你的 Strapi 內容類型。 從內容類型建構器將它們匯出為 JSON。將每個對應到 Payload 集合配置。
  2. 在新 Next.js 專案中設置 Payload。 執行 npx create-payload-app@latest,然後選擇 PostgreSQL 適配器。
  3. 將 Payload 指向你的 Supabase 資料庫。 建立新的 Supabase 專案,取得連線字串,配置適配器。
  4. 在 TypeScript 中重新建立架構。 這是大部分工作。每個 Strapi 內容類型都成為一個 Payload 集合。欄位幾乎 1:1 對應——文本、數字、富文本、關係、媒體。
  5. 從 Strapi 匯出資料。 如果你在 PostgreSQL 上,使用 pg_dump,或根據 Strapi REST API 編寫指令碼以提取所有內容。
  6. 匯入 Payload。 在種子指令碼中使用 Payload 的 Local API 來大量建立內容。
  7. 更新前端。 將 Strapi API 呼叫交換為 Payload Local API 呼叫(在伺服器元件中)或 REST/GraphQL 呼叫(在客戶端元件中)。
  8. 部署。 由於 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 (separate) 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 也是如此。不要過度工程化它。
  • 你需要邊界優先的性能。 如果全球延遲低於 50ms 是硬性要求,請查看 Cloudflare Workers 上的 SonicJS。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 是一個堅實的選項,特別是如果你有一個現有的 SQL 資料庫,你想通過 CMS 介面公開。它聰明地從你的資料庫架構自動生成管理面板和 API。與 Payload 相比的主要缺點是缺乏深度 Next.js 整合——Directus 作為單獨的服務執行,類似於 Strapi。如果你的團隊不在 Next.js/Vercel 堆疊上,Directus 值得認真考慮。

我可以在 Vercel 上部署 Payload + Supabase 嗎? 絕對地——這實際上是理想的部署目標。由於 Payload 在你的 Next.js 應用內執行,部署到 Vercel 就像推送到你的 Git 儲存庫一樣簡單。Supabase 作為託管服務執行,所以那邊沒有什麼可部署的。你的總基礎設施變成:Vercel 用於計算和 CDN,Supabase 用於資料庫和認證。兩個服務,一個部署管道。我們經常通過我們的 Next.js 開發實踐為客戶設置這個。

Payload 管理面板可自訂嗎? 非常。管理 UI 是使用 React 構建的,支援自訂元件、自訂檢視和自訂欄位。你可以新增儀表板小工具、建立自訂導覽項目並覆蓋任何預設 UI 元素。自 Payload 3.x 起,管理自訂使用 React 伺服器元件,這意味著你的自訂管理代碼可以在伺服器端提取資料,而無需 API 呼叫。這與 Strapi 的管理擴充系統完全不同,後者需要移除和修補。

在生產環境中執行此堆疊的成本是多少? 對於小型到中型專案:Vercel Pro,$20/月 + Supabase Pro,$25/月 = $45/月總計。這提供無伺服器計算、託管 PostgreSQL 資料庫,8GB 儲存、250MB 檔案儲存、50,000 個月活躍認證使用者和自動備份。從那裡向上擴展。將其與在 VPS 上自主託管 Strapi($20-50/月)加上管理你自己的資料庫或 Strapi Cloud 的增長計劃 $45/月(座位有限)進行比較。Payload + Supabase 組合在成本上具有競爭力,並且運作起來非常容易。有關詳細的專案估計,請查看我們的定價頁面