Vercel + Next.js + Supabase + Claude API 堆疊:無需 CMS
開發者正在放棄 CMS 的原因,以及 2026 年更好的替代方案
我已經用 headless CMS 平台建立網站多年了。Contentful、Sanity、Strapi -- 你能說出來的,我都整合過。但在 2025 年末左右,我開始注意到一個模式:對於越來越多的專案,我根本沒有使用 CMS。相反,我用 Next.js 在 Vercel 上、Supabase 作為資料和認證、Claude API 處理任何內容智能需求來運送完整的全棧應用。沒有 CMS 廠商。沒有內容建模 UI。沒有按月計費的座位許可。
這不是為了標新立異。確實有很多專案適合用 headless CMS -- 我們在 Social Animal 建立了很多這樣的專案(看看我們的headless CMS 開發工作)。但有一類特定的應用,這種無廠商棧不僅可行,而是更好。讓我詳細為你介紹它的工作原理、何時使用它,以及如何從零開始設定。
目錄
- 為什麼開發者正在放棄 CMS
- 堆疊概覽
- 在 Vercel 上設定 Next.js 專案
- Supabase 作為後端:認證、資料庫和儲存
- 整合 Claude API 進行內容智能
- 構建自訂管理介面
- 真實成本:這個堆疊實際成本是多少
- 何時仍應使用 CMS
- 生產部署檢查清單
- 常見問題
為什麼開發者正在放棄 CMS
讓我們誠實地談談 CMS 提供的東西:一個非技術人員編輯內容的 UI、一個結構化的資料層、也許還有一些媒體管理,以及一個 API 來取得所有這些。當你有一個行銷團隊每天發佈文章時,這確實很有價值。
但這是我在 2026 年一直看到的:
- SaaS 產品,其中「內容」是用戶生成的資料,而不是編輯副本
- 內部工具,其中團隊足夠技術化,可以直接編輯資料庫或使用輕量級管理面板
- AI 原生應用,其中內容即時生成、摘要或轉換
- 初創公司無法為 CMS 辯護 $300-500/月 的成本,當他們只有三個用戶時
對於這些專案,CMS 是開銷。你為不會使用的內容建模功能付費,管理一項服務的 API 密鑰,該服務基本上只是一個花哨的資料庫包裝器,並且需要處理 webhook 複雜性來保持同步。
替代方案?完全擁有你的資料層。Supabase 為你提供 Postgres(一個真正的資料庫,不是專有的內容存儲)、認證、檔案儲存和即時訂閱。Claude 處理智能層。Next.js 和 Vercel 處理其他一切。
堆疊概覽
| 層級 | 技術 | 角色 | 2026 年定價(起價) |
|---|---|---|---|
| 前端和 API | Next.js 15 (App Router) | UI、Server Components、Route Handlers | 免費(開源) |
| 託管和邊緣 | Vercel | 部署、CDN、無伺服器函數 | 免費層 / $20/月 Pro |
| 資料庫和認證 | Supabase | Postgres、行級安全性、認證、儲存 | 免費層 / $25/月 Pro |
| AI 層 | Claude API (Anthropic) | 內容生成、摘要、分類 | 按令牌計費(約 $3/$15 每 100 萬令牌用於 Sonnet 4) |
| 管理 UI | 自訂(React + Supabase) | 你的團隊的內容管理 | $0(你自己構建) |
中等流量的生產應用的總成本:$45-100/月。與典型的 headless CMS 設定相比,僅 CMS 本身就可能花費 $99-500/月,更不用說你還要為託管付費。
在 Vercel 上設定 Next.js 專案
我假設你已經有 Node.js 20+ 和一個 Vercel 帳戶。如果你是 Next.js 的新手,我們的團隊在我們的Next.js 開發能力頁面上已經廣泛撰寫過它。
npx create-next-app@latest my-app --typescript --tailwind --app --src-dir
cd my-app
Next.js 15 配合 App Router 是這裡的基礎。我們預設使用 Server Components,這意味著大多數數據獲取發生在伺服器上 -- 沒有暴露的 API 密鑰,沒有初始內容的客戶端載入旋轉器。
這是我為這個堆疊的典型專案結構:
src/
├── app/
│ ├── (public)/ # 行銷頁面、文章
│ ├── (dashboard)/ # 經過認證的管理區域
│ │ ├── layout.tsx # 認證檢查包裝器
│ │ ├── posts/
│ │ ├── media/
│ │ └── settings/
│ ├── api/
│ │ ├── ai/ # Claude API 路由
│ │ └── webhooks/ # Supabase 即時鉤子
│ └── layout.tsx
├── lib/
│ ├── supabase/
│ │ ├── client.ts # 瀏覽器客戶端
│ │ ├── server.ts # 伺服器客戶端
│ │ └── admin.ts # 服務角色客戶端
│ ├── claude.ts # Anthropic SDK 包裝器
│ └── utils.ts
├── components/
└── types/
環境變數
你在 .env.local 中需要這些:
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-key
ANTHROPIC_API_KEY=sk-ant-...
部署到 Vercel
推送到 GitHub。在 Vercel 中連接該 repo。添加你的環境變數。完成。我不會詳述這一點 -- Vercel 對 Next.js 部署的開發者體驗是業界最好的,你可能已經知道它是如何工作的。
值得注意的一件事:如果你需要功能標誌或配置在不重新部署的情況下更新,請使用 Vercel 的 Edge Config。這是一個小事,但它替代了另一個 SaaS 工具。
Supabase 作為後端:認證、資料庫和儲存
這是魔力發生的地方。Supabase 不只是「Firebase 但用 Postgres」-- 它是一個完整的後端平台,你實際上擁有它。你的資料存放在標準 PostgreSQL 資料庫中。如果你曾經想要離開,你 pg_dump 然後離開。試試用專有的 CMS 做這個。
資料庫模式
假設你正在構建一個內容驅動的應用(你通常會為了 CMS 而使用的東西)。這裡有一個模式,可以處理文章、媒體和基本分類法:
-- 啟用 UUID 生成
create extension if not exists "uuid-ossp";
-- 內容表(替代你的 CMS 內容模型)
create table public.posts (
id uuid default uuid_generate_v4() primary key,
title text not null,
slug text unique not null,
body text, -- Markdown 內容
excerpt text,
status text default 'draft' check (status in ('draft', 'published', 'archived')),
author_id uuid references auth.users(id),
featured_image text, -- Supabase Storage 路徑
metadata jsonb default '{}', -- 靈活的欄位,無需遷移
published_at timestamptz,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
-- 標籤 / 分類法
create table public.tags (
id uuid default uuid_generate_v4() primary key,
name text unique not null,
slug text unique not null
);
create table public.post_tags (
post_id uuid references public.posts(id) on delete cascade,
tag_id uuid references public.tags(id) on delete cascade,
primary key (post_id, tag_id)
);
-- 行級安全性
alter table public.posts enable row level security;
-- 任何人都可以讀取已發布的文章
create policy "Public can read published posts"
on public.posts for select
using (status = 'published');
-- 經過認證的用戶可以管理自己的文章
create policy "Authors can manage own posts"
on public.posts for all
using (auth.uid() = author_id);
那個 metadata jsonb 欄位是關鍵。它為你提供了 CMS 自訂欄位的靈活性,而無需每次行銷團隊想要新欄位時運行遷移。需要 SEO 描述?metadata->>'seo_description'。需要 Open Graph 圖像覆蓋?metadata->>'og_image'。在你需要靈活性的地方它是無模式的,在你需要完整性的地方是結構化的。
認證設定
Supabase Auth 處理一切。電子郵件/密碼、魔法連結、使用 Google/GitHub 的 OAuth -- 這一切都已內置。
// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
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)
)
},
},
}
)
}
檔案儲存
Supabase Storage 替代了你的 CMS 擁有的任何媒體庫。建立一個名為 media 的桶,設定一個策略,你就有了一個帶有自動 CDN URL 的 S3 相容檔案存儲。
// 上傳一個檔案
const { data, error } = await supabase.storage
.from('media')
.upload(`posts/${slug}/${file.name}`, file, {
cacheControl: '3600',
upsert: false,
})
// 獲取公共 URL
const { data: { publicUrl } } = supabase.storage
.from('media')
.getPublicUrl(`posts/${slug}/${file.name}`)
整合 Claude API 進行內容智能
這是 2026 年堆疊最與傳統 Web 開發不同的地方。Claude API 不只是一個聊天機器人 -- 它是一個智能層,可以替代整個 CMS 插件和第三方服務類別。
這是我在生產中使用它的用途:
- 自動生成 SEO 元數據來自文章內容
- 內容摘要用於摘錄和社交卡片
- 內容分類和自動標籤
- 智能搜尋理解意圖,而不只是關鍵詞
- 草稿協助用於內容作者
設定 Anthropic SDK
npm install @anthropic-ai/sdk
// lib/claude.ts
import Anthropic from '@anthropic-ai/sdk'
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
})
export async function generateSEOMetadata(content: string, title: string) {
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [
{
role: 'user',
content: `Given this article title and content, generate SEO metadata.
Title: ${title}
Content: ${content.slice(0, 3000)}
Respond with JSON only:
{
"seo_title": "50-60 char title with primary keyword",
"seo_description": "120-160 char meta description",
"excerpt": "1-2 sentence hook for social sharing",
"suggested_tags": ["tag1", "tag2", "tag3"]
}`,
},
],
})
const text = message.content[0].type === 'text' ? message.content[0].text : ''
return JSON.parse(text)
}
export async function classifyContent(content: string, existingTags: string[]) {
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 256,
messages: [
{
role: 'user',
content: `Classify this content into the most relevant tags from the existing list. You may suggest up to 2 new tags if nothing fits.
Existing tags: ${existingTags.join(', ')}
Content: ${content.slice(0, 2000)}
Respond with JSON: { "tags": ["tag1", "tag2"], "new_tags": ["maybe-new"] }`,
},
],
})
const text = message.content[0].type === 'text' ? message.content[0].text : ''
return JSON.parse(text)
}
AI 功能的 API 路由
// app/api/ai/seo/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
import { generateSEOMetadata } from '@/lib/claude'
export async function POST(request: NextRequest) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { content, title } = await request.json()
try {
const metadata = await generateSEOMetadata(content, title)
return NextResponse.json(metadata)
} catch (error) {
return NextResponse.json(
{ error: 'AI generation failed' },
{ status: 500 }
)
}
}
這裡的成本可以忽略不計。一個典型的 SEO 元數據生成呼叫可能使用大約 4,000 個輸入令牌和 200 個輸出令牌。以 Claude Sonnet 4 的定價約 $3/100 萬輸入令牌和 $15/100 萬輸出令牌,那大約是每個呼叫 $0.015。你可以為 1,000 篇文章生成元數據,花費約 $15。
構建自訂管理介面
這是讓人們感到緊張的部分。「如果我沒有 CMS,非技術人員如何編輯內容?」
你構建一個簡單的管理 UI。在 2026 年,「簡單」實際上是簡單的。這是一個基本文章編輯器組件:
// app/(dashboard)/posts/[id]/editor.tsx
'use client'
import { useState } from 'react'
import { createBrowserClient } from '@supabase/ssr'
export function PostEditor({ post }: { post: Post }) {
const [title, setTitle] = useState(post.title)
const [body, setBody] = useState(post.body || '')
const [saving, setSaving] = useState(false)
const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
async function save() {
setSaving(true)
const { error } = await supabase
.from('posts')
.update({
title,
body,
updated_at: new Date().toISOString(),
})
.eq('id', post.id)
setSaving(false)
if (error) alert('Save failed: ' + error.message)
}
async function generateSEO() {
const res = await fetch('/api/ai/seo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, content: body }),
})
const metadata = await res.json()
// 應用生成的元數據到文章
await supabase
.from('posts')
.update({ metadata, excerpt: metadata.excerpt })
.eq('id', post.id)
}
return (
<div className="max-w-4xl mx-auto p-6">
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="text-3xl font-bold w-full mb-4 border-b pb-2"
/>
<textarea
value={body}
onChange={(e) => setBody(e.target.value)}
className="w-full h-96 font-mono text-sm p-4 border rounded"
/>
<div className="flex gap-4 mt-4">
<button onClick={save} disabled={saving}
className="px-4 py-2 bg-blue-600 text-white rounded">
{saving ? 'Saving...' : 'Save Draft'}
</button>
<button onClick={generateSEO}
className="px-4 py-2 bg-purple-600 text-white rounded">
✨ Generate SEO Metadata
</button>
</div>
</div>
)
}
是的,這是一個簡單的 textarea。在一個真實的專案中,你會換上像 Tiptap、MDXEditor 或 BlockNote 這樣的東西用於富文本編輯。重點是:管理介面是你的代碼。你控制每個像素、每個工作流、每個權限。無需與 CMS UI 限制搏鬥。
對於更複雜的專案,考慮 Refine 或 AdminJS 作為直接連接到 Supabase 的管理面板框架。它們會為你節省數週。
真實成本:這個堆疊實際成本是多少
讓我們為一個內容豐富的網站做一些月度 10 萬次頁面瀏覽量的具體數字:
| 服務 | 層級 | 月度成本 | 你得到的 |
|---|---|---|---|
| Vercel | Pro | $20 | 1TB 頻寬、1000 GB-小時無伺服器 |
| Supabase | Pro | $25 | 8GB 資料庫、250GB 頻寬、10 萬 auth 用戶 |
| Claude API | 按使用量付費 | ~$10-30 | ~500 萬令牌/月(SEO 生成、摘要、搜尋) |
| 域名 | 年度 | ~$1 | .com 域名 |
| 總計 | $56-76/月 |
現在比較這與典型的 headless CMS 堆疊:
| 服務 | 層級 | 月度成本 |
|---|---|---|
| Contentful | Team | $300 |
| Vercel | Pro | $20 |
| Algolia (搜尋) | Build | $50 |
| Auth0 (認證) | Essentials | $35 |
| 總計 | $405/月 |
那是 5-6 倍的成本差異。而且 Supabase 堆疊為你提供了更多靈活性,而不是更少。
何時仍應使用 CMS
我想對此有清楚的認識。不要為每個專案放棄你的 CMS。headless CMS 仍然是更好的選擇,當:
- 大型編輯團隊需要結構化工作流(批准鏈、排程、超越基本 RBAC 的角色)
- 內容是產品-- 發佈商、媒體公司、有數百名貢獻者的文檔網站
- 你需要視覺編輯-- 某些 CMS 平台提供實時預覽和視覺建構者,複製需要幾個月
- 多通道交付-- 如果相同的內容供應網站、行動應用、數字標牌和電子郵件,CMS 的結構化內容模型證明了其價值
- 大規模本地化-- 像 Contentful 和 Sanity 這樣的 CMS 平台擁有成熟的 i18n 工作流
我們仍然在 Social Animal 構建大量 headless CMS 專案。如果那是你的專案需要的,與我們談論它。但對於越來越多的應用類別,其中它不是你需要的,停止為它付費。
生產部署檢查清單
在你將此堆疊運送到生產之前,運行此清單:
- 行級安全性策略針對每個表進行測試(Supabase 的策略模擬器在這裡有幫助)
- 速率限制 Claude API 路由(使用 Vercel 的
@vercel/edge速率限制器或 upstash/ratelimit) - 輸入驗證在所有 API 路由上(Zod 是你的朋友)
- 錯誤邊界在你的 React 樹中用於 AI 失敗(Claude 偶爾會超時)
- 快取策略-- 在 Next.js 中對資料庫支持的頁面使用
unstable_cache或revalidateTag - 監控-- Vercel Analytics 用於性能、Supabase Dashboard 用於資料庫指標、Anthropic Console 用於 API 使用情況
- 備份策略-- Supabase Pro 包括每日備份,但也設定邏輯複製或
pg_dumpcron 以確保安心 - 內容安全策略標頭在
next.config.js中配置 - 圖像最佳化-- 使用 Next.js
<Image>組件配合 Supabase Storage URL
常見問題
Supabase 真的能替代 headless CMS 嗎? 對於許多用例,是的。Supabase 為你提供一個 PostgreSQL 資料庫,其中包含一個 REST 和 GraphQL API 自動從你的模式生成、檔案儲存、認證和即時訂閱。它沒有提供的是一個開箱即用的優質內容編輯 UI -- 你需要自己構建它或使用像 Refine 這樣的工具。如果你的團隊是技術性的或規模很小,這個權衡絕對值得。
典型網站的 Claude API 成本是多少? 對於使用 Claude 進行 SEO 元數據生成、內容摘要和基本分類的內容網站,預計花費 $10-30/月(中等使用量,數百個 AI 操作)。Claude Sonnet 4 在 2026 年的定價大約是每 100 萬輸入令牌 $3,每 100 萬輸出令牌 $15。單個 SEO 元數據生成呼叫的成本大約 $0.01-0.02。
這個堆疊適合企業應用嗎? 這取決於你對企業的定義。Vercel 和 Supabase 都提供企業級層,具有 SLA、SOC 2 合規性和專屬支援。該堆疊可以很好地處理高流量 -- Next.js 在 Vercel 上自動擴展,Supabase Pro 支援連接池和讀副本。對於合規性重的行業,你會希望 Supabase 的自託管選項以將資料保留在你自己的基礎設施中。
沒有 CMS 的情況下如何處理內容預覽和草稿工作流?
你構建它們。Next.js Draft Mode 結合 posts 表中的 status 欄位為你提供草稿/已發布工作流。對於預覽,創建一個經過認證的路由,無論狀態如何都獲取文章。這大約是 50 行代碼,相比在 CMS 儀表板中配置預覽 URL。
在沒有 CMS 的情況下如何處理富文本編輯?
使用現代富文本編輯器庫。Tiptap(基於 ProseMirror 構建)是 2026 年最受歡迎的選擇 -- 它支援協作編輯、自訂塊、斜槓命令和 Markdown 快捷方式。BlockNote 是另一個不錯的選擇,具有 Notion 風格的 UI。將輸出存儲為 HTML、Markdown 或 JSON 在你的 Supabase body 欄位中。
我可以從 headless CMS 遷移到這個堆疊嗎? 絕對可以。大多數 headless CMS 平台都有匯出 API。編寫一個遷移指令碼,從你的 CMS API 拉取內容並將其插入 Supabase 表中。我們已經為幾個客戶進行了這個遷移,從 Contentful 和 Sanity 轉移到 Supabase 支持的設定。最困難的部分通常是將 CMS 的專有富文本格式對應到標準 HTML 或 Markdown。
如果 Supabase 宕機會怎樣? Supabase 在 2025-2026 年保持了良好的正常運行時間,但沒有服務是完美的。因為你的資料存放在標準 PostgreSQL 中,你有選項:設定讀副本、在 S3 中保留自動備份,或甚至運行備用實例。如果你在 Supabase 的自託管層上,你完全控制基礎設施。這實際上比依賴 CMS 廠商更有彈性 -- 如果 Contentful 出現故障,你不能只是「切換到另一個 Contentful」。
我應該對文章或行銷網站使用此堆疊嗎? 對於開發者的個人文章或初創公司的行銷網站,這個堆疊是完美的。你獲得完全控制、最少的成本和 AI 驅動的功能,在 CMS 中會需要昂貴的外掛。對於每週發佈 20+ 篇文章的大型行銷團隊,具有複雜的批准工作流,你可能會想要一個適當的 CMS。這是關於將工具與團隊匹配。如果你不確定哪種方法適合你的專案,請查看我們的定價頁面或與我們聯繫進行快速諮詢。