Flat-file CMS · PHP 8.2+ · MIT
Counterglow Pages are folders.
A content system without a database. Every page is a folder, every text a plain file. Copy it, commit it, edit it on a plane, hand it to someone who has never heard of this software. It keeps working.
In progress · open source
At a glance
Counterglow is a free, open-source flat-file CMS written in pure PHP 8.2 or newer by Dirk Gerber (Gerber.Media). Pages are folders and content is plain text, so there is no database, no build step and no vendor directory. It comes with a web panel, eleven themes, responsive images, SVG layout templates, a sitemap, an RSS feed and JSON search built in. Content files are byte-compatible with Kirby. Licence: MIT.
- Language
- PHP 8.2 or newer, GD recommended
- Database
- none
- Dependencies
- none, not even Composer packages
- Licence
- MIT
- Status
- in progress
The folder is the page
The folder name carries the URL, the sort order and the status. Changing the status in the panel just renames the folder. Pick a folder to see what a visitor gets.
content/
cover.jpg and cover.jpg.txt sit next to it: the image and its alt text.
Title: About ---- Text: A short story of how this site came to be.
About
Appears in menus and feeds, sorted first.
Title: Why flat files outlive databases ---- Date: 2026-02-14 ---- Tags: architecture, content ---- Text: Markdown goes here, with **bold**, lists, tables and code fences.
Why flat files outlive databases
The file name picks the template: note.txt renders through note.php.
Title: Imprint ---- Text: Who is responsible for this site.
Imprint
Reachable by its URL, hidden from listings.
Title: An idea for later ---- Text: Not ready yet.
An idea for later
Only visible when you are signed in.
What is inside
The YAML parser, the Markdown parser, the image pipeline and the panel are all written for this project.
Content tags
Rich components without writing HTML:
(image: cover.jpg caption: …), galleries, video, files. Register your own from a plugin.Templates
A template is a PHP file with
$pageand$siteready. Fields are chainable and never null; collections filter, sort and paginate.Responsive images
image()writes srcset, dimensions and lazy loading. Renditions are generated once and cached as static files.SVG layout templates
Draw a layout in Inkscape, Figma or Illustrator, name layers like
cg-text-titleorcg-link-notes, and the CMS fills them from the content.Every SVG sanitised
Uploads are cleaned on the way in and templates on the way out, against an allowlist. No scripts, no event handlers, no resources from other sites.
Headless when you want
/sitemap.xml,/feed.xml,/robots.txt,/search.json?q=…and every page as.json.The panel
Server-rendered, about nine kilobytes of JavaScript. ⌘K palette, ⌘S save, split Markdown preview, drag and drop. The essentials work without JavaScript.
Accounts and roles
Admin, editor, author. Accounts are PHP files with bcrypt hashes, every POST carries a CSRF token, failed logins back off exponentially.
Eleven themes, one content folder
A theme only ships what it changes. Every lookup checks the theme first and falls back to /site. Switch in the panel under System → Theme.
- HaloEditorial: serif display type, drop caps, printed paper.
Accent #b4402c - UmbraDark and monospaced for docs and changelogs.
Accent #5fd68a - PrismImage-first: split-screen hero, full-bleed photos.
Accent #7b5cf0 - Counter NewsTech news: lead story, card grid, reading progress.
Accent #e5372b - HandbookDocumentation with a sidebar that maps the site.
Accent #2563eb - MeridianOversized grotesk, generous whitespace.
Accent #2f5bff - PorcelainAiry, hairline rules, a quiet sage accent.
Accent #5f7a58 - BoardroomStructured for reports and business writing.
Accent #1a56db - GraphiteModern dark with one signal-lime accent.
Accent #c6f24a - GripSkate-zine: condensed caps, thick ink rules.
Accent #ff4d17 - EyelinerAfter-hours: ink-black, hot magenta, italic serif.
Accent #ff2d76
Running in one line
You need PHP 8.2 or newer. GD is recommended for image resizing.
Start the built-in server in the project folder:
php -S localhost:8000 router.phpOpen
localhost:8000/paneland create the first account. That is the whole installation.
On a real server
Upload the folder and make content/, media/, site/accounts/ and logs/ writable. Nothing to compile, migrate or seed. Apache rules ship in .htaccess, an nginx example is in the README.
Back up content/ and site/ and you have backed up the entire site.
What comes next
Counterglow is in progress. The next steps, in this order:
- RevisionsThe last ten versions of every page, kept on save.
- Redirects on renameA new slug writes a redirect, so old links keep working.
- Content exportA ZIP of content/ straight from the panel.
- Landing page generatorBuilt on the SVG slot mechanism.
Questions
Does Counterglow need a database?
No. Pages are folders and content is plain text files. Back up the folder and you have backed up the site.
Can I move existing Kirby content?
Yes. The content files are byte-compatible with Kirby, so a content folder can be moved across without a migration script.
What does Counterglow cost?
Nothing. It is open source under the MIT licence, and the code is on Codeberg.
Which hosting does it need?
Any web host with PHP 8.2 or newer. There is no Composer, no npm and no build step, so uploading the folder is enough.
Can I use it headless?
Yes. Every page is also available as JSON, and search runs at /search.json.
Read the code, keep the folder.
Questions, ideas or bug reports? Write to me. hello@gerber.media