The Cloudbase Foundation · Internal Documents

cloudbase.foundation — CMS and build-cost options

cloudbase.foundation — CMS and build-cost options

Date: 2026-08-07 · Owner: Jonathan · Status: Options for discussion — no decision taken Context: raised when a deploy took longer than expected on launch day. Related: post-launch roadmap

What the build actually costs

Measured against the repo on 2026-08-07.

What we publish 12 routes, 13 content files (10 JSON, 3 Markdown)
Packages installed per build 1,806
node_modules 2.1 GB
Attributable to TinaCMS ≥468 MB@tinacms 178 · tinacms 54 · react-icons 84 · monaco-editor 76 · mermaid 76
Tina admin UI shipped to the Worker 11 MB, 92 files, on every deploy

There are no stray dependencies. Direct dependencies are six runtime (next, react, react-dom, next-intl, tinacms, @tinacms/cli) and nine dev. react-icons, monaco-editor and mermaid are not ours — npm ls traces all three to tinacms alone. The tree is Tina.

The build is three sequential passes: tinacms build (generates a schema and typed GraphQL client, then indexes content against Tina Cloud over the network), next build, then opennextjs-cloudflare build, which re-bundles the whole Next server into one Worker.

The tinacms build pass is the disproportionate one. It needs TINA_TOKEN exported, it requires a 4 GB heap — it died with "Reached heap limit" on 3 August — and it makes network round-trips to a hosted service. That cost is fixed. It would not shrink if we deleted every page, and it will not grow much as content grows.

What Tina is buying us

Not nothing — this is the part that makes the decision real rather than obvious.

Worth noting the split we already run: narrative content is in Tina, but UI microcopy lives in messages/en.json / es.json and is edited by developers, in git, with no CMS at all. So both models are already in production here.

The coupling, honestly

Every fetching page.tsx imports the generated client and calls client.queries.<name>({ relativePath }), then passes data, query and variables into a *PageClient.tsx that calls useTina() and uses generated TypeScript types. That is roughly 12 files across six page pairs, plus the tina/ directory.

The content itself is already plain JSON and Markdown in the repo. Nothing is locked in a proprietary store — this is a code-coupling problem, not a data- migration problem. That is what makes every option below tractable.


Option 1 — Keep Tina, cache the install · in progress

Turn on Build Caching in Workers Builds. Nothing else changes.

The honest first move regardless of what we decide long-term — it is cheap and it tells us how much of the wait is install versus Tina.

How: Cloudflare dashboard → the cbf-site Worker → Settings → Builds → Build Caching. It is a dashboard setting, still in beta; there is no wrangler command and nothing in wrangler.toml for it, so it cannot be scripted or code-reviewed. Whoever enables it should note the date here.

Baseline to beat — measured on the launch-day deploy, uncached:

PR #14 merged 2026-08-07 14:27:16Z
Worker deployment created 2026-08-07 14:46:48Z
Wall clock 19 min 32 s

The next push after caching is enabled is the comparison. If it lands near 19 minutes, the install was never the problem and the cost is Tina and OpenNext — which makes Option 3 considerably more attractive. If it drops sharply, Option 1 may be the whole answer and the rest of this document can wait.

Either way the number is worth recording here rather than remembered.

Option 2 — Keep Tina for editing, remove it from the build

Read content/*.json directly at build time and delete the GraphQL layer. Editors keep using Tina, which commits to the repo as it does now; the site simply stops querying it.

The awkward middle. It removes the build cost but keeps the dependency, so the saving is smaller than it looks.

Option 3 — Replace Tina with PagesCMS

We already run PagesCMS on the documents repo. Same organisation, same pattern, known quantity, no new vendor and no new account.

PagesCMS is entirely external — it edits files in the repo through GitHub and contributes zero npm packages and zero build steps.

Strongest candidate on the numbers, and the least novel — we would be consolidating on a tool we already operate rather than adopting one.

Option 4 — No CMS

Content edited in git by developers, like messages/*.json already is.

Named for completeness and for the honest reason that it is the cheapest to build. Recommending it would mean deciding the principle was wrong — which is a board-level call about how the organisation works, not an engineering one.


For the discussion

  1. Do Option 1 now regardless. It is cheap, reversible, and it produces the measurement the rest of this depends on.
  2. The real question is 3 versus 1. Is a polished editing experience with live preview worth ~468 MB, a build pass and a hosted dependency — for thirteen content files?
  3. Who actually edits, and how often? Two people, forty times in three months. If that is the steady state, it is worth asking whether it justifies the heaviest thing in the stack.
  4. What we do not know yet: the wall-clock split between install, Tina, Next and OpenNext. Nobody has read a Workers Build log for this project. We now have a total — 19 min 32 s uncached — but not a breakdown. Option 1 gives us the comparison; the build log itself would give us the split. Any decision made before both is a guess.

Nothing here is a recommendation to act during launch week.