Strapi is the most popular open source headless CMS by some distance — about
73,000 GitHub stars and 2,800 Stack Overflow questions. If you self-host the
Community edition, it is free, capable, and someone has already solved your
problem on the internet.
This comparison is not about that Strapi. It is about the two places Strapi's
model starts to hurt: when you have more than one project, and when the
project succeeds.
#Strapi Cloud bills per project. corpusctl doesn't have projects to bill.
Strapi Cloud pricing, taken from strapi.io on 17 August 2026:
Overages: +$1.50 per 25,000 API requests, +$0.60 per GB of storage,
+$30 per 100 GB of bandwidth. Extra environments are +$60/month on Pro and
+$300/month on Business.
Read the header of the price column again: per project.
An agency with ten client sites is looking at ten separate subscriptions. Not
ten spaces on one bill — ten projects, each with its own request allowance, its
own storage allowance, and its own overage meter running independently. At
Starter that is $350 a month before a single client outgrows 100,000 requests.
corpusctl does not have a per-project line because a project is not a billing
unit. One panel, unlimited spaces, and a user carries a separate role in each
space — editor for one client, owner for another, invisible on a third.
Isolation is enforced by PostgreSQL row-level security, in the database,
below the application layer where the mistakes happen.
The Starter allowance divides out to roughly 3,300 requests a day.
A typical page renders from more than one call — the entry, the navigation, the
related posts. At three calls per page view you reach the ceiling at about
1,100 daily page views. Then add the crawlers, the preview requests, the
uptime monitor, and the front-end that forgot to cache during a deploy.
After that, every 25,000 requests costs $1.50. It is not a large number. It is
just a number that goes up precisely when things are going well, and one you
cannot forecast, because it is driven by strangers.
And on Starter, the instance sleeps when idle. That is a cold start on the
first request after a quiet period — on the marketing site you are paying to
make fast.
corpusctl has no request allowance because published content is never served by
the API. Hitting publish writes the rendered content to an immutable,
hash-addressed file in object storage and refreshes a manifest. The visitor's
client resolves the slug to a manifest shard locally, then fetches that
immutable address from the nginx edge cache — cacheable for thirty days,
because the same address can never return different content.
Two HTTP requests, both from cache. Neither reaches the API. Neither reaches
PostgreSQL. There is nothing to count.
#Self-hosting Strapi is free — and that is the honest comparison
If you self-host the Community edition, none of the above applies, and you
should weigh that seriously. What you are then comparing is operational
surface.
Strapi self-hosted gives you the CMS. You still assemble and operate the rest:
the database, the object storage for media, a search backend if you need one,
a queue for webhook delivery, the cache, the reverse proxy, and the upgrade path
across major versions.
corpusctl ships the whole set as one deployment — PostgreSQL, Valkey,
Typesense, Garage, nginx — with a self-hosted install available on the
Enterprise plan. Every component runs on your own infrastructure. There is no
third-party service in the stack billed per usage; that is a product constraint,
not a current pricing decision.
Which of these is better depends entirely on whether you want to own that
operational surface. Some teams do, and they should pick Strapi.
Turning a feature off. In corpusctl every feature is a module — media,
search, webhooks, SEO, GraphQL, import, analytics. disabled preserves the
data and resumes where it left off; uninstalled clears it and asks twice.
A plan downgrade sets modules to disabled and never deletes data. That is
a rule in the codebase, not a support policy.
What the client library imposes. corpusctl's block renderers ship with
zero default styling — not one line of CSS. Any block type can be
overridden, and an unknown block type is skipped rather than throwing. The core
render tree is framework-agnostic; React, Vue and Next.js adapters are thin
layers on top. A CMS that ships opinionated markup has not solved the "render
the API response" problem, it has renamed it.
Webhook delivery. Deliveries sit in a durable queue with exponential
backoff and jitter. If your receiver is down for an hour, the events are still
there when it comes back.
Error codes. Every API error carries a permanent code (CORPUS_E_9127) and
a documentation link. Messages are translated into seven languages; codes are
not. Client code binds to the code, so improving a message never breaks an
integration.
Community. Roughly 73,000 GitHub stars and 2,800 Stack Overflow questions
against corpusctl's much smaller footprint. When you hit an edge case at 2am,
the odds that someone has already written it up are dramatically better with
Strapi. This is a real advantage and it compounds.
Plugin ecosystem. Strapi has a marketplace of plugins and providers.
corpusctl has none — integrations are written against webhooks and the API.
Maturity. Strapi has shipped through several major versions with a large
installed base. corpusctl is young; SSO and a contractual SLA are on the
roadmap, which is the polite way of saying they do not exist yet.
Free forever, self-hosted. The Community edition costs nothing and always
has. That is hard to argue with, and we are not going to try.
Pick Strapi if you want to self-host for free, you value a large community, or
you need plugins you would otherwise have to write.
Pick corpusctl if you run several projects from one place, want isolation
enforced by the database, and want an invoice that does not move when a post
does well.
Strapi Cloud prices taken from strapi.io/pricing-cloud
on 17 August 2026, excluding local taxes. Prices change — check before quoting.