Project · Headless CMS

TachyonCMS: A Rust Headless CMS That Shouldn't Make You Pick a Side

Pick a CMS and you usually pick a side: a joy to code against, or easy for the person publishing the newsletter. TachyonCMS is my attempt at both, as one Rust binary on one Postgres database. It's pre-alpha, and the API half works today.

0.1.0Pre-alpha, no release yet
384Tests, run on Postgres 16, 17 and 18
0Unsafe blocks, forbidden by the compiler
MITOpen source

Overview

Pick a CMS today and you usually pick a side. One kind is typed, API-first and a pleasure to code against, and it baffles whoever has to publish the Tuesday newsletter. The other is WordPress: easy to publish with, and you pay for that ease in plugins, patches and page speed.

I don’t think you should have to choose. TachyonCMS is a headless CMS written in Rust: one binary, one Postgres database, and an API generated from the content types you define. I started it on 12 October 2026, and I’m building it in public.

The problem

Content types change. “Title” should have been “headline”. The “summary” field never earned its keep. In most systems that’s a migration you write by hand, at night, hoping no document is shaped the way you forgot about.

Then there’s who can see what. Real sites don’t stop at “editors edit”. Visitors see what’s published, authors see their own drafts, and the salary field is for HR. Bolt that on in application code and sooner or later one endpoint forgets to check.

What I built

Define a collection over the API and the endpoints exist straight away. Text, numbers, dates, selects, slugs, relationships to one collection or several, map points you can search by distance, groups and repeatable lists, all arranged in rows, tabs and collapsible sections that shape the editing screen without touching your data. Get something wrong and the error names the exact field, seo.title or links.0.url, in the standard RFC 9457 format with a request ID you can find in the logs.

Reads take whatever shape you ask for:

curl 'localhost:3000/api/posts?where[author.name][equals]=Ann&sort=-publishedOn&select[title]=true'

That filters through a relationship, sorts, and sends back only the titles, plus their IDs. Populate linked documents with depth=2, list the posts that point at a category with a join field, or show the author’s name on every post with a virtual field that’s never stored.

When the schema changes, TachyonCMS carries your documents across. A rename keeps its data. Anything that would delete or retype data comes back first as a preview: what changes, how many documents it touches, which ones won’t validate. It only goes through when you send it again with "confirm": true. Rather keep content types in Git? Export them to JSON, review the diff like code, and apply it from the command line.

Security I can point at

“Highly secure” is easy to type. Here’s what it means in this repo today.

There’s no unsafe code, and the compiler refuses to build if anyone adds some. Every query is either checked against the schema at compile time by SQLx, or built from a validated filter tree with bound parameters. Passwords are hashed with Argon2, need 12 characters, and get refused if Have I Been Pwned has seen them, checked by sending only the first five characters of a hash. Five wrong passwords in 15 minutes locks the account for 15 minutes.

Access rules live in the schema, and a read rule becomes part of the database query wherever a document can appear: lists, single reads, populated links, joins, virtual fields, and filters through relationships. So nobody can probe for a hidden document with where[author.team]=red. GET /api/access tells each caller what they’re allowed to do, so an admin screen can hide the buttons that would fail. The README even lists what the rules can’t hide yet, like a unique field giving away that some document holds a value.

And fast? There are no benchmarks yet. I’ll publish reproducible ones against the popular CMSs before I quote you a single number.

Where it is now

Pre-alpha, and the README opens by saying so. No release, no Docker image, no tag. The content API works, and so do sign-in with sessions, bearer tokens and scoped API keys, four built-in roles plus your own, and access rules on collections, globals and fields. Every pull request runs the test suite against Postgres 16, 17 and 18.

What doesn’t exist yet: the admin UI, media, drafts and versions, GraphQL. Those are on a twelve-milestone roadmap that runs through to a WordPress importer and release builds, and the editor’s side is what comes next. Until it lands, please don’t put it on a public network.

Try it

You’ll need Rust and Docker:

git clone https://github.com/tachyon-cms/tachyoncms.git
cd tachyoncms
cp .env.example .env
docker compose up -d
set -a; source .env; set +a
cargo run -p tachyon -- serve

The server listens on 127.0.0.1:3000 and refuses every change until you create the first Admin. The README walks you through that, then your first content type and your first post, in five curl commands. The code is on GitHub, and if you’d like one email when it launches, the site will send exactly that.

// Let's talk

You have ideas.
I have IT solutions.

Fifteen minutes on Zoom is usually enough to tell whether I'm the right person for what you're building.

Denver, CO · Available for architecture, infrastructure, and DevOps engagements