Cobalt

Architecture

How Cobalt's pieces fit together.

Monorepo layout

apps/
  worker/       Cloudflare Worker (Hono), API + site serving
  docs/         This documentation site
packages/
  database/     Drizzle ORM schema, migrations, DB client
tooling/
  typescript/   Shared tsconfig presets
  eslint/       Shared ESLint flat config

More apps (dashboard) and packages (auth, ui, seo, analytics, editor, api, storage, shared, config) land as their respective phases of development begin.

Single-tenant by design

Each Cobalt deployment serves exactly one site. There's no workspace layer, no billing, no subdomain routing between tenants. Want a second site? Deploy Cobalt again. This keeps the schema simple: content tables aren't scoped by a tenant ID anywhere, because there's only ever one tenant per deployment.

Site-wide configuration, name, domain, timezone, lives in a single-row site_settings table. The database enforces the single row with a check constraint, not application logic.

Data layer

Postgres via Drizzle ORM, reached from the Worker through Cloudflare Hyperdrive so requests don't pay a cold-connection penalty. Locally, the Worker connects directly using a DATABASE_URL from .dev.vars. In production it reads from the Hyperdrive binding instead.

Roles

Roles live directly on the users table. No membership table, since there's only one site to be a member of:

RolePublishEdit others' posts
adminYesYes
editorYesYes
authorOwn posts onlyNo
contributorDrafts onlyNo

License

Cobalt is licensed under AGPL-3.0. Modify Cobalt and run it as a network service for others, and you're required to make your modified source available to them too.

On this page