Most content management systems assume a server that is always on, a managed database, and a monthly bill to match. Ghostlite started from the opposite premise: what if the entire platform had to fit inside a free plan?
The four pieces
Cloudflare's free tier hands you four primitives that, together, cover everything a small blog needs:
Pages hosts the rendered site and the edge functions.
D1 stores structured metadata — posts, users, tags.
R2 holds the heavy content: post bodies and uploaded media.
KV caches rendered HTML so repeat reads never touch the database.
None of these carry a per-hour cost. You pay only once you outgrow the genuinely generous free limits, and a personal blog rarely does.

What you give up
The trade is real. There is no long-lived process, so background jobs need a separate paid Worker. There is no SMTP, so transactional email goes through an HTTP API instead. And the database is young — D1 is excellent, but it is not Postgres.
Constraints are not the enemy of good architecture. They are the brief.
A quick example
Reading a post is two calls away — metadata from D1, body from R2:
const post = await getPublishedPostBySlug(env.DB, slug);
const body = await readPostBody(env.R2, post.body_key);The rendered result is cached in KV under a key that includes the publish timestamp. Edit the post and the key changes, so readers always see fresh content. It is a small system, and that is exactly the point.