DEV Community

Foisal Islam
Foisal Islam

Posted on

I wanted WordPress habits without a PHP stack, so I built OpenPress

There is a specific kind of fatigue that shows up when you already live in TypeScript, but the publishing tool everyone knows is still PHP.

You know the admin. Posts, pages, media, themes, plugins, roles. Your brain already has the map. What you do not want is another MySQL + plugin-directory world bolted onto a Node codebase, or a headless CMS that makes every editor relearn how to publish.

That gap is why OpenPress exists.

The awkward middle

On one side you have WordPress. It wins on familiarity and ecosystem. It also means PHP, a plugin model that shares a process with your site, and a migration story that is its own career path.

On the other side you have modern TypeScript CMS options. Many of them are excellent. A lot of them feel like developer tools first and publishing tools second. The admin is powerful, but it does not feel like the thing non-technical editors already trust.

I kept wanting the first experience with the second stack.

So OpenPress is intentionally boring in the places WordPress trained people: the admin chrome, the content model, the idea of themes and plugins. The interesting part is underneath.

What it actually is

OpenPress is a self-hosted CMS. MIT license. Monorepo.

  • API: NestJS
  • Web / admin / public site: Next.js
  • Database: PostgreSQL
  • Package manager: pnpm (turbo for the workspace)

Current release on GitHub is v1.0.0. Repo: github.com/foisalislambd/openpress.

There is no separate marketing site yet and no hosted demo. The README includes a short walkthrough video, gifs, and screenshots under docs/ so you can see the admin before you clone anything.

Familiar on purpose

If you have used wp-admin, the shape should feel known:

  • Posts and pages
  • Block editor
  • Revisions, plus autosave that does not spam revision history
  • Drafts, scheduling, trash
  • Public / private / password visibility
  • Sticky posts, excerpts, SEO fields
  • Categories, tags, custom fields
  • Media library with an upload allow-list, alt text, captions, and generated sizes
  • Roles: Admin, Editor, Author, Contributor, Subscriber
  • JWT access/refresh tokens, plus application passwords for scripts
  • Appearance: themes, primary/footer menus, sidebar/footer widgets
  • Tools: WordPress WXR import, among other ops bits

That list is not a promise of full WordPress parity. Gutenberg block plugins, multisite, and the official plugin directory are still on the roadmap. The point of shipping now is a usable WordPress-shaped core on a typed stack, not a fake “we replaced everything” claim.

Plugins without sharing your process

This was one of the sharp edges I cared about.

In classic WordPress, a plugin runs in the same process as the site. That is powerful. It is also how one bad add_action becomes everyone’s outage.

OpenPress keeps WordPress-shaped hooks — actions and filters with familiar names — but each plugin runs in its own process. Content, storage, email, and HTTP are separate permissions. HTTP is limited to an allow list. An admin reviews that list before install. Packages can be signed, and a bad release can be rolled back.

The plugin zip is small conceptually: a plugin.json and a main file that exports activate(ctx). Hooks are always available. Everything else is a permission.

That is not a marketplace yet. The public directory comes later. What exists today is the contract: isolated process, declared permissions, review before install, rollback if it goes wrong.

Importing a real WordPress export

A lot of “WordPress alternatives” treat import as a nice-to-have and flatten everything into drafts.

OpenPress’s WXR import keeps private, password, and scheduled posts as those things. It can download public attachments and show progress. Re-uploading the same export updates existing posts instead of duplicating them blindly.

If you have ever lost scheduled posts in a migration, that sentence is the whole pitch.

How to run it

From the repo:

git clone https://github.com/foisalislambd/openpress.git
cd openpress
pnpm install
cp apps/api/.env.example apps/api/.env
cp apps/web/.env.example apps/web/.env
Enter fullscreen mode Exit fullscreen mode

Start PostgreSQL 14+ (Docker Compose is in the repo, or pnpm db:local), then:

pnpm db:migrate
pnpm db:seed
pnpm dev
Enter fullscreen mode Exit fullscreen mode

After that:

Seeded local login (development only): admin@openpress.local / admin12345. Change it before any shared deploy.

There is also a production Compose file if you want to build images yourself. Release assets on GitHub include Compose files and a source tarball for v1.0.0.

Requirements: Node.js 20+, pnpm 10+, PostgreSQL 14+.

Who this is for

OpenPress fits if:

  • Your team already ships React/Node
  • Editors still think in posts, pages, media, themes, plugins
  • You want self-hosted, MIT, and a real Postgres database
  • You care about plugin isolation more than “install anything from a giant directory today”

It is the wrong fit if you need the WordPress plugin directory, Gutenberg block plugins, or multisite right now. Those are written down as later work, not pretend features.

Why ship a CMS in 2026

Because the publishing UX people trust and the stack developers trust still do not live in the same house often enough.

You should not have to choose between “editors know this admin” and “the codebase is TypeScript end to end.” OpenPress is one attempt to put those in the same monorepo, with process-isolated plugins and a WordPress import that does not throw away visibility.

If that problem sounds familiar, clone it, break it, open issues, or tell me which WordPress habit is still missing for your team.

Repo again: https://github.com/foisalislambd/openpress

MIT. Self-hosted. No PHP runtime.

Top comments (0)