the headless CMS that runs on your Postgres

schema-as-code, draft-vs-published clarity, and content in plain Postgres tables. open source, Apache-2.0, self-host free forever.

pepper — migration

pepper migrate --from hygraph

reading hygraph schema and fields

mapping to chili.config.ts (schema-as-code)

writing migrations + RLS policies

generated an import plan for review

done. your content runs on your Postgres now.

  • SQLquery your content directly
  • $0self-host, free forever
  • RESTstable delivery path today
  • 60sfrom container to first entry
schema-as-code

your content model lives in chili.config.ts

the schema is canonical in code, not clicked together in a GUI you can't review. you write models, fields, and relations in chili.config.ts, and the Studio generates the editing UI from that file.

schema changes ship the way code ships. they land in a pull request, get reviewed, and run as a migration. no drift between what an admin clicked last quarter and what your repo says is true.

  • fields, relations, and enums typed in one file
  • the GUI is a generator, never the source of truth
  • schema diffs review like any other code change
a chili.config.ts excerpt defining a post model.
draft / publish

every save is a draft until you publish it

nothing goes live by accident. each save writes a draft, and the entry stays in draft until an editor publishes it on purpose. the published state carries a real green colour, a filled dot, and a "live" label, so status never rides on colour alone.

scheduled publishing and preview tokens let a content lead stage a launch. an editor sees what is live across thirty entries at a glance, and a typo never ships because someone hit the wrong button.

  • draft and published are separate states, not a flag
  • published reads as success-green + dot + label
  • schedule a publish or hand out a preview token
the entries list, draft and live states marked by shape and label.
live preview

preview is the default view, not a tab

editors edit against the rendered site, not a raw form in isolation. the canvas is a 55/45 split: the form on the left, your actual site rendering on the right, updating as they type.

the preview renders the customer's site. our Studio chrome never bleeds into that pane, so what an editor sees is what a reader gets.

  • 55/45 form-and-preview split, single-column form
  • the preview renders your site, not our chrome
  • no tabs hiding form sections (one scroll, top to bottom)
the editor canvas: form on the left, rendered preview on the right.
delivery API

rest-first delivery, graphql for built-ins, sdk helper

REST is the stable delivery path today. GraphQL covers the built-in content graph, and the SDK gives you a generic typed helper while generated per-model clients mature.

the schema still has one source of truth: chili.config.ts. as generated clients land, they should come from that same file instead of a second API description.

  • REST delivery from the content model
  • GraphQL over the built-in content graph
  • generic SDK helper today; generated clients next
the same published entry read over REST and the SDK helper.
multi-tenant

tenant isolation enforced in postgres, not app code

every tenant table runs FORCE ROW LEVEL SECURITY. the database refuses to return another tenant's rows even if the application asks, so isolation does not depend on a where-clause someone might forget.

middleware sets app.tenant_id per transaction from a verified JWT, and the policy does the rest. one project can host many tenants on one Postgres without trusting application code to stay perfect.

  • ENABLE + FORCE ROW LEVEL SECURITY on every tenant table
  • tenant id set per transaction from a verified JWT
  • no superuser role in app code, ever
a row-level-security policy and the per-request tenant binding.

everything from one schema

the model you write in code drives the editor, the API, and the isolation — no second source of truth.

postgres-native, not postgres-backed

your content lives in real Postgres tables you can query, index, and back up. no proprietary store, no lock-in — point psql at it and read.

rest today, graphql where it fits

REST is the stable delivery path today. GraphQL covers the built-in content graph, and the SDK gives a typed helper while generated per-model clients mature.

self-host, free forever

Apache-2.0 core, no feature paywall. one container plus your Postgres. deploy it on a $40 box and keep your data.

multi-tenant on row-level security

tenant isolation is enforced in Postgres with FORCE ROW LEVEL SECURITY, not in app code you have to trust.

tiptap editing, draft until you publish

a real rich-text editor on Tiptap. every save is a draft; nothing goes live until you publish it.

flat studio, fast editing

the Studio keeps gradients out of data surfaces so repeated editing stays calm. your content path is one app container plus Postgres.

read it however you build

the same published post over REST, GraphQL for the built-in content graph, and the generic SDK helper.

bash
curl https://api.chilicms.dev/v1/posts \
  -H "Authorization: Bearer $CHILI_TOKEN"

how we compare

we mark where we lose, not just where we win. our cloud is younger and our plugin marketplace is smaller — both are honest gaps.

how we compare — we mark where we lose, not just where we win. our cloud is younger and our plugin marketplace is smaller — both are honest gaps.
capabilityChiliCMSContentfulHygraphStrapi
schema-as-code, version-controlledthe content model lives in your repo
self-host free foreverApache-2.0 core, no feature paywall
runs on your own Postgresno proprietary datastore
REST + GraphQL + SDK
row-level-security multi-tenancyenforced in the database, not app code
hosted cloud maturitywhere we lose today — our cloud is younger
marketplace of pluginsanother honest gap — Strapi's is larger

product questions

Where does my content actually live?

In real Postgres tables in your own database. You can point psql at it, index it, and back it up like any other table. There is no proprietary store in front of it, so leaving ChiliCMS does not mean exporting from a black box.

How do schema changes get reviewed?

You edit chili.config.ts and open a pull request. The diff reviews like any code change, then runs as a migration. The Studio generates its editing UI from that file, so the GUI never becomes a second, unreviewed source of truth.

Do I have to use GraphQL?

No. REST is the stable delivery path today, GraphQL covers the built-in content graph, and the SDK exposes a generic typed helper. Generated per-model clients are the intended next step, not something we pretend is already complete.

Is multi-tenancy safe out of the box?

Every tenant table runs ENABLE plus FORCE ROW LEVEL SECURITY. Middleware sets the tenant id per transaction from a verified JWT, and the policy filters every read. Isolation does not depend on app code remembering a where-clause.

What does the cloud cost, and what is free?

Self-hosting the Apache-2.0 core is free forever. The hosted cloud is priced on workspace shape (members, environments, locales, entries), not on API calls, and the Enterprise floor is printed publicly on the pricing page. No per-call metering, no contact-us wall under $5k.

run a real cms on your own postgres

Schema-as-code, draft-until-published clarity, and REST-first delivery. Apache-2.0, self-host free forever.