
Security News
PHP Foundation Says Chainguard Broke Security Embargo Ahead of Emergency Patches
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.
A little CMS with big heart β schema-driven content management that runs entirely on Cloudflare's free tier.
Koguma gives you a headless CMS with a beautiful admin dashboard, all powered by Cloudflare Workers + D1 + R2. Define your content types in code, and Koguma handles the rest β API routes, admin UI, media storage, and a file-based content/ directory for version-controlled content.
bun add koguma
# or
npm install koguma
Create a site.config.ts in your project root:
import { defineConfig, contentType, field } from 'koguma';
export default defineConfig({
siteName: 'My Site',
contentTypes: [
contentType({
id: 'post',
name: 'Blog Post',
displayField: 'title',
fields: {
title: field.text('Title').required(),
slug: field.text('Slug').required(),
body: field.markdown('Body'),
heroImage: field.image('Hero Image'),
published: field.boolean('Published').default(false),
date: field.date('Published Date')
}
})
]
});
Create a worker.ts:
import { createWorker } from 'koguma/worker';
import config from './site.config';
export default createWorker(config);
Create koguma.toml:
name = "my-site"
database_id = "" # filled by `koguma init`
That's it β two lines. Everything else is derived by convention:
my-site-dbmy-site-mediamy-sitekoguma init # Scaffold project, create D1 + R2 on Cloudflare
koguma push # Build + deploy + sync content
Your admin dashboard is at /admin. Your API is at /api/content/:type.
| Field | Usage | Stored As |
|---|---|---|
field.text(label) | Titles, slugs, URLs | TEXT |
field.longText(label) | Descriptions, bios | TEXT |
field.markdown(label) | Rich formatted content | TEXT (markdown string) |
field.number(label) | Counts, order | number in JSON |
field.boolean(label) | Toggles | boolean in JSON |
field.date(label) | Timestamps | string (ISO 8601) |
field.select(label, {options}) | Dropdowns | string |
field.url(label) | URLs | string |
field.email(label) | Email addresses | string |
field.phone(label) | Phone numbers | string |
field.color(label) | Hex colours | string |
field.youtube(label) | YouTube video IDs | string |
field.instagram(label) | Instagram handles | string |
field.image(label) | Image from R2 media | string (asset ID) |
field.images(label) | Array of images | string[] (asset IDs) |
field.ref(typeId, label) | Link to another entry | string (entry ID) |
field.refs(typeId, label) | Array of entry links | string[] (entry IDs) |
All fields stored inside a JSON data blob in the entries table β no per-field columns, no migrations.
contentType({
id: "page",
name: "Page",
displayField: "title",
singleton: true, // Only one entry allowed (e.g. site settings)
fields: { ... },
});
All commands auto-detect your project root by looking for koguma.toml.
| Command | Description |
|---|---|
koguma init | Interactive project setup β scaffold, create D1 + R2, set secret |
koguma dev | Auto-sync content/ β local D1, generate types, start dev server |
koguma push | Build + deploy + sync content to remote |
koguma pull | Download remote content + media β local content/ files |
koguma gen-types | Generate koguma.d.ts typed interfaces |
koguma tidy | Validate content/ against config, sync dirs, check fields |
Koguma uses a content/ directory for file-based content that lives in your git repo:
content/
βββ post/ # folder = content type ID
β βββ hello-world.md # file = one entry
β βββ our-mission.md
βββ siteSettings/
β βββ index.md # singletons use index.md
βββ media/ # optional local images
βββ hero-banner.jpg
Markdown files with frontmatter:
---
title: Our Mission
slug: our-mission
heroImage: hero-banner.jpg
published: true
date: 2026-03-01
---
## Who We Are
Rich text body, stored as markdown.
Git is your version history. No custom versioning table needed.
| Method | Route | Description |
|---|---|---|
GET | /api/content/:type | List all entries of a content type |
GET | /api/content/:type/:id | Get a single entry (with resolved refs) |
GET | /api/media/:key | Serve a media file from R2 |
| Method | Route | Description |
|---|---|---|
POST | /api/auth/login | Login with { password } |
POST | /api/auth/logout | Clear session |
GET | /api/auth/me | Check authentication |
GET | /api/admin/schema | Content type schemas (for admin UI) |
GET | /api/admin/:type | List entries |
GET | /api/admin/:type/:id | Get entry |
POST | /api/admin/:type | Create entry |
PUT | /api/admin/:type/:id | Update entry |
DELETE | /api/admin/:type/:id | Delete entry |
GET | /api/admin/media | List media assets |
POST | /api/admin/media | Upload media (multipart form) |
DELETE | /api/admin/media/:id | Delete media |
References and images are automatically resolved to nested objects in the public API (up to 2 levels deep).
import { defineConfig, contentType, group, field, type Infer } from 'koguma';
import { createWorker } from 'koguma/worker';
import { createClient } from 'koguma/client';
import { Markdown, useEntry, useEntries } from 'koguma/react';
import type { KogumaAsset, EntryReference } from 'koguma/types';
# Create .dev.vars with your local admin password
echo "KOGUMA_SECRET=your-password" > .dev.vars
# Start dev server (auto-syncs content/, generates types)
koguma dev
# Admin dashboard is at http://localhost:8787/admin
# API is at http://localhost:8787/api/content/:type
Your Project
βββ site.config.ts β Content type definitions
βββ worker.ts β Entry point (imports koguma/worker)
βββ koguma.toml β Project config (name + database_id)
βββ .dev.vars β Local secrets (KOGUMA_SECRET)
βββ content/ β Version-controlled content files
βββ post/
β βββ hello-world.md
βββ siteSettings/
βββ index.md
Koguma (this package)
βββ src/
β βββ config/ β Schema definitions (defineConfig, field types)
β βββ api/ β Hono router (CRUD + media + auth)
β βββ db/ β D1 queries (JSON document store)
β βββ auth/ β HMAC-signed cookie sessions
β βββ media/ β R2 upload/serve/delete
β βββ admin/ β Dashboard HTML shell + JS/CSS bundle
β βββ client/ β Fetch client for consuming the API
β βββ react/ β React hooks + <Markdown> component
βββ admin/ β Vite + React admin dashboard source
βββ cli/ β CLI commands (init, dev, push, pull, gen-types, tidy)
MIT
FAQs
π» A little CMS with big heart β schema-driven, runs on Cloudflare's free tier
The npm package koguma receives a total of 2 weekly downloads. As such, koguma popularity was classified as not popular.
We found that koguma demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 1 open source maintainer collaborating on the project.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.