Cloudflare vs Supabase for the Client CMS — 2026-07-28 Re-Read

Author: hermes · Date: 2026-07-28 · Tier: T-deep (decision-grade — every load-bearing claim verified against a primary source this session; source ledger at the end) Requirement, as stated: "a user authentication CMS system where our clients can log in and upload data and add their own data and publish blog posts." Prior arc reviewed: research/cms-basketball-vercel-handover-2026-07-15/ (arm 1, handover) · research/cms-managed-hosting-model-2026-07-15/ (arm 2, managed) · research/directus-cms-2026-05-22/ · decision hermes#116 This is a delta re-read, not a restart. The 13-day-old arc did the landscape work. One thing changed underneath it, and it changes the answer.


TL;DR

  1. The prior CMS verdict stands: Payload v3. Nothing found this session weakens it. Directus is still the better turnkey editor over an existing Postgres; Payload is still the only candidate that runs natively on Cloudflare compute and keeps both business models (handover + managed) open.

  2. What changed: Payload now ships an official Cloudflare D1 adapter. @payloadcms/db-d1-sqlite (3.85.0) plus a first-party with-cloudflare-d1 template and a Deploy to Cloudflare button that provisions the Worker, a D1 database and an R2 bucket, pre-bound. The 2026-07-15 report assumed Payload-on-Workers must reach a Supabase Postgres via Hyperdrive. That assumption is now optional, and an all-Cloudflare path with no Supabase at all is real.

  3. "Cloudflare vs Supabase" is not the fork. Cloudflare is compute + CDN + object storage; Supabase is Postgres + Auth + Storage. They overlap only in data and identity. The real fork is: does the client's data live in D1 (SQLite, inside Cloudflare) or in Supabase Postgres (outside it)?

  4. On the requirement as written, Supabase's strongest card is never played. "Clients log in, upload, publish" is editor-class auth, which Payload's own user store and role system already provides — the 07-15 arc ruled exactly this (T2: do not stand up Supabase Auth for content editors). Supabase Auth only becomes load-bearing if the public site later needs member accounts. Cloudflare has no consumer-identity equivalent — but the claim needs sharpening, and did not have it when first written (re-checked 2026-07-28 under the brief's null-search rule). Cloudflare does now ship a first-party IdP: Cloudflare as identity provider (changelog 2026-05-19), default login method for new Zero Trust organisations since 2026-06-18. It authenticates users with their existing Cloudflare account, and "authentication is restricted to members of your account" — so it is workforce/Access identity, not CIAM for your app's end users. Access remains seat-priced (free ≤50, then $7/user/mo). searched: “Cloudflare identity product for application end users 2026 sign-in customer accounts” · “Cloudflare Workers authentication library D1 sessions users 2026 official” · “Cloudflare 2026 first-party user authentication product Workers better-auth OR OpenAuth OR CIAM end user login D1”. as-of: 2026-07-28.

  5. Cost at fleet scale is not close. All-Cloudflare: $5/month per account (not per site) + usage, with 5 GB D1 storage, 25 B rows read and 50 M rows written included, and 50,000 D1 databases per account. Supabase: $25/month plus roughly $10/month of compute per additional project. At 10 client sites that is ≈$5–15/mo vs ≈$115/mo.

  6. Recommendation — all-Cloudflare becomes the default tier; Supabase becomes the deliberate upgrade. This refines hermes#116 option 3 (tier by complexity) rather than overturning it — same shape, different contents. Trigger to upgrade a client to the Supabase tier: public end-user accounts, relational/reporting workloads, or a contractual portability guarantee that wants pg_dump.


1. What we already decided (the 13-day-old arc, still standing)

Prior finding Status today Note
Payload v3 is the CMS pick (both arms) ✅ holds, strengthened The D1 adapter removes its last dependency on a second vendor
Directus is the most Supabase-data-native, but needs an always-on VM ✅ holds — re-checked under rule #18 §3 Two different disqualifiers, previously conflated as "cannot run on Cloudflare compute": (a) Workers — capability-absent, and vendor-documented as to why: Directus needs persistent DB/Redis connections, a local filesystem and persistent memory, none of which the Workers runtime provides (directus/directus discussion #15572); self-hosting requirements are Node 22 + Docker. (b) Containers — cost-disqualified, not capability-disqualified: a Directus image can run there; Containers bill for bursty/sleep-capable workloads, which an always-on CMS is not. Decomposed per the ratified §3 — each half carries its own date because they perish on different clocks: CLAIM A Directus runtime requirements (persistent connections / filesystem / memory; Node 22 + Docker) — SEARCHED: “Directus changelog 2026 hosting requirements Node runtime edge deployment” · AS-OF: 2026-07-28. CLAIM B Cloudflare compute capabilities (Workers runtime; Containers billing shape) — SEARCHED: “Directus deploy Cloudflare Workers Containers 2026 self-host serverless support” · AS-OF: 2026-07-28. A changes on Directus's release cadence; B changes whenever Cloudflare ships or re-prices.
Do not stand up Supabase Auth for content editors — the CMS's own invite/role flow is the login ✅ holds, and is the key to this decision CMS↔Supabase-Auth SSO reconciliation is paid/enterprise on all three; do not walk into it
One isolated CMS instance per client, not shared multi-tenancy ✅ holds D1's 50,000-databases-per-account limit makes per-client isolation cheaper, not more expensive
Cloudflare Containers are not cost-effective for always-on Directus ✅ holds Unchanged since GA 2026-04-13
Media on R2 (no egress fees) ✅ holds Now provisioned automatically by the Payload template
Managed model, $600–1,200/yr, with a mandatory data-export exit clause ✅ holds — but see §4 The exit clause is harder to honour from SQLite than from Postgres. This is the one place the new default costs you something
hermes#116: Vite+Supabase vs Next+Payload as house default — open, leaning "tier both" 🔄 this report is the missing input The Minos build proved the light tier; this proves the heavy tier can be cheaper than assumed

Reality anchor from hermes#116: the first real client (Minos / Neukölln Minotaurs) was an existing Vite+React+Supabase SPA, and a Supabase-direct in-app CMS was simpler and sufficient. That case is unaffected by anything here — you do not migrate an existing Supabase app to D1. Everything below is about the greenfield default.


2. What actually changed since 2026-07-15

2.1 Payload on Cloudflare D1 — the material change

2.2 Cloudflare's 2026 releases — mostly not about us

Agents Week 2026 (13–17 April) was an agent-infrastructure event: Dynamic Workers, Sandboxes GA, Mesh, AI Gateway as a unified inference layer, Artifacts (git-compatible versioned storage), Email Service beta, and a new unified cf CLI. None of it changes a CMS build. The one adjacent item is Managed OAuth for Access (open beta, changelog 2026-03-20): it lets non-browser clients — CLIs, agents, SDKs — authenticate to Access-protected apps via standard OAuth 2.0. Per Cloudflare's own docs it is "a new transport mechanism, not a separate authentication path" — Access policies still govern, and the identity still comes from an IdP. It is not consumer login.

2.3 Supabase's 2026 releases — sharpen the upgrade tier

June 2026: a $500 M Series F, Multigres 0.1, passkey auth (WebAuthn; only the public key is stored server-side), a ChatGPT integration with 29 management tools, and token-based database access. Pricing is unchanged in shape: Free (paused after 1 week idle, 2 active projects), Pro $25/mo (100,000 MAU included, 8 GB disk/project, 100 GB storage, 250 GB egress, one Micro instance via a $10/mo credit), Team $599/mo.

Read against our requirement: none of it is needed for editor login — all of it matters the moment the public site needs member accounts. That is precisely the upgrade trigger in §4.


3. The comparison, against this requirement

Axis All-Cloudflare (Workers + D1 + R2 + Payload) Cloudflare + Supabase (Workers + Hyperdrive→Postgres + R2/Supabase Storage)
Client/editor login ("log in… publish") Payload's own user store, invites, roles Identical — Payload's own auth. Supabase Auth adds nothing here
Public member accounts (not asked for, plausible later) ❌ no first-party CIAM. Cloudflare's own IdP (2026-05-19, default since 06-18) is Access-scoped and restricted to account members. The real path is third-party on Workers — Better Auth has a maintained Cloudflare integration (better-auth-cloudflare: D1, KV, Hyperdrive, migrations), which is a build you own and patch ✅✅ Supabase Auth — 100,000 MAU on Pro, passkeys, MFA, OAuth providers, and RLS wired to the same identity
Data store D1 (SQLite): 10 GB/database (Paid), 5 GB storage and 50,000 databases included per account, unlimited rows per table, single-threaded per database, read replication in beta Postgres: 8 GB disk/project included then $0.125/GB, RLS, extensions, full-text, pgvector, realtime, branching
Write concurrency One writer per database, serialized. Irrelevant for a blog/CMS; disqualifying for a write-heavy app Real concurrency
Uploads / media R2, auto-bound by the template, no egress fees R2 the same, or Supabase Storage (RLS-aware, image transforms) with 100 GB included and $0.09/GB egress beyond 250 GB
Backups Time Travel: always on, no extra cost, restore to any minute in the last 30 days (7 on Free) Pro: automated daily backups (14-day retention on Team); pg_dump any time
Moving parts per site 1 vendor, 1 compute, 0 extra hosts 2 vendors
Cost, 10 client sites ≈$5–15/mo total ($5/account minimum + usage; per-site marginal cost ≈ $0 at this scale) ≈$115/mo ($25 + ~$10/mo compute × 9 extra projects)
Exit / portability (contractual clause) SQLite export — workable, but "here is your database" means a .sqlite file plus R2 objects pg_dump to any Postgres host. Strictly the more credible promise to write into a contract
Vendor concentration DNS + CDN + compute + data + storage all Cloudflare. Operationally simple; a single blast radius Data survives a Cloudflare-side decision; a second bill and a second status page
Known blockers Paid Workers required; GraphQL not guaranteed on Workers Hyperdrive hop adds a moving part; free-tier projects pause, so Pro is the floor for live sites

The honest framing of the cost gap

The ~$100/mo difference at 10 sites is not the interesting part — it is ~$1,400/yr against upkeep revenue the prior arc priced at $600–1,200/yr per client. At 10 clients that is $6,000–12,000/yr of revenue, so infra is a rounding error in both models. The gap matters for a different reason: it is the difference between "a new client site costs me nothing to stand up" and "a new client site costs me $10/mo before anyone has visited it." That changes how freely you can take on small clients, pilots and unpaid prospects — which is a business-shape question, not an accounting one.


4. Verdict

For the requirement as stated — clients log in, upload data, add their own data, publish blog posts — go all-Cloudflare: Payload v3 on Workers + D1 + R2.

Reasoning, in order of weight:

  1. The stated requirement never exercises Supabase's differentiator. Editor auth is the CMS's job, already ruled. Paying a second vendor for Postgres + Auth buys capability the brief does not ask for.
  2. Per-client isolation gets cheaper, not dearer. 50,000 D1 databases per account against ~$10/mo per extra Supabase project inverts the prior arc's cost table.
  3. Fewer moving parts per site was already the deciding criterion in the managed arm. This removes one more.
  4. The workload is a blog CMS. D1's real constraints — 10 GB and one writer per database — are nowhere near a small client site.

Upgrade a client to the Supabase tier when any of these is true (each is a real trigger, not a hypothetical):

What this does to hermes#116: it keeps option 3 (tier by complexity) but rewrites both tiers. The light tier is Supabase-direct in-app CMS for clients who already have a Supabase app (proven by Minos). The default greenfield tier becomes Payload on Workers + D1 + R2. The Supabase-Postgres-under-Payload combination — the 07-15 recommendation — survives only as the upgrade configuration, not the default.


5. What would change this verdict


Source ledger

# Claim Source Tier
1 Official Payload D1 adapter @payloadcms/db-d1-sqlite 3.85.0; template provisions Worker + D1 + R2; Paid Workers required; GraphQL not guaranteed payloadcms/payload templates/with-cloudflare-d1/README.md (fetched) + npm listing deep-read
2 D1 limits: 10 GB/db Paid, 500 MB Free; 50,000 dbs/account; 1,000 queries per invocation; single-threaded per database; read replication beta developers.cloudflare.com/d1/platform/limits/ (fetched) deep-read
3 D1 pricing: 5 GB storage, 25 B rows read, 50 M rows written included on Paid; $0.75/GB-mo beyond developers.cloudflare.com/d1/platform/pricing/ (fetched) deep-read
4 D1 Time Travel: always on, no extra cost, any minute within 30 days (7 on Free) developers.cloudflare.com/d1/reference/time-travel/ (fetched) deep-read
5 Workers Paid: "minimum charge of $5 USD per month for an account"; 10 M requests + 30 M CPU-ms included developers.cloudflare.com/workers/platform/pricing/ (fetched) deep-read
6 Supabase pricing/limits: Free (2 projects, pauses after 1 week), Pro $25 (100 k MAU, 8 GB disk, 100 GB storage, 250 GB egress, one Micro via $10 credit), Team $599 supabase.com/pricing (fetched) deep-read
7 Managed OAuth for Access — open beta, OAuth 2.0 transport over existing Access policies, RFC 9728 discovery; not a separate auth path Cloudflare changelog 2026-03-20 + Cloudflare One docs (search-surfaced summary) snippet
8 Cloudflare Access seat model: free ≤50 users, $7/user/mo beyond, one seat per authenticating identity multiple 2026 pricing trackers; not confirmed against Cloudflare's own pricing page this session snippet ⚠
8b Negative claim — no first-party Cloudflare CIAM for app end users. Re-checked under the null-search rule: Cloudflare's own IdP exists but is Access-scoped/account-member-restricted; the CIAM path on Workers is third-party (Better Auth + D1/KV) CF changelog 2026-05-19 + 2026-06-18; better-auth-cloudflare. searched: three query strings, listed inline at the claim snippet, terms named
9 Agents Week 2026 releases (Dynamic Workers, Sandboxes GA, Mesh, AI Gateway, Artifacts, Email Service, cf CLI) cloudflare.com/agents-week/updates + secondary recaps snippet
10 Supabase June 2026: $500 M Series F, Multigres 0.1, passkey auth, ChatGPT integration secondary tech press snippet ⚠
10b Absence-based disqualifier — Directus has no Workers-runtime path (capability), and Containers is a cost disqualifier rather than a capability one. Re-checked under rule #18 §3 as ratified 2026-07-28 Directus self-hosting requirements (Node 22/Docker) + directus/directus discussion #15572 + CF Containers docs. SEARCHED: two query strings at the claim · AS-OF: 2026-07-28 snippet, terms named
11 Prior-arc verdicts (Payload v3, Directus VM requirement, T2 auth ruling, per-client isolation, pricing model) research/cms-managed-hosting-model-2026-07-15/REPORT.md, hermes#116 file-sourced

Load-bearing rows are 1–6, all deep-read. Rows 8 and 10 are flagged: the Access seat price and the Supabase funding/passkey details come from secondary sources, and no verdict above rests on either — Access is ruled out on shape (workforce ZTNA, not consumer identity), which its own product docs establish, not on price.