Serving WordPress without PHP
A WordPress page view starts a PHP worker. The worker loads WordPress core, your theme and each active plugin, opens a connection to a MySQL server, runs the loop, and tears most of it down again. It does this for each request.
Your site is the content, the theme that renders it, and the admin you edit it with. BookPress keeps those three and replaces what runs underneath.
The serving path is a C++ rewrite from the ground up. The router, the block-theme renderer, the query layer and wp-admin are native code, not PHP. PHP runs only for your themes and plugins, on BookPress's own PHP engine. A site with no plugins does all of its work without running any PHP.
You can try one. The live demo is the
Kadence theme with WooCommerce, Elementor, Yoast SEO, Contact Form 7, Yoast Duplicate Post and Hello Dolly all active, served by this
engine on a Google Cloud e2-micro with no page cache in front of
it. Your login appears when you start your sandbox. Write a post. The sandbox
is deleted 15 minutes after you start it, so put nothing personal into
it.
The engine
- Compiled to native code. C++ built for modern Intel and ARM Linux servers, with hand-optimised request parsing and HTML generation. WordPress core runs as native code and plugins run as PHP on our own engine. The whole server is a 1.8 MB binary.
- Embedded SQLite storage. The database is SQLite, running in-process on the same WordPress schema. Content queries return in microseconds, and no database server sits in the request path.
- Workers sized to the machine. At start, BookPress sets its number of workers from the machine's processors and memory. A number you set overrides it. We measured the figures on this page with four workers.
- PHP compiled at start. BookPress compiles a site's PHP files at startup and again when a file changes. The first visitor does not wait for compilation.
Real theme rendering
BookPress renders WordPress block themes natively. It reads
the same template files, the same block markup and the same
theme.json, and produces the HTML and CSS that WordPress produces:
global styles, layout classes, font presets, fluid typography. Twenty
Twenty-Five, the default WordPress theme, renders pixel-close today from its
unmodified theme files, web fonts included.
The admin follows the same approach. /wp-login.php checks your
existing WordPress password hashes. /wp-admin gives you the
dashboard, post lists and editor, served by the same engine at the same
speed.
What we compared: a hard test for BookPress
We take a real site: the Kadence theme with WooCommerce, a built Elementor showcase page, Yoast SEO and Contact Form 7. We migrate the identical content into both engines, with the same row counts in both databases. We tune the WordPress side as a competent host would before measuring it: PHP 8.3.35 with OPcache and the JIT enabled, a Redis object cache over a socket, MariaDB, and PHP-FPM behind nginx, with WooCommerce's newer order storage (HPOS) switched on. We time a page only after checking that WordPress and BookPress show the same page: the same Elementor markup, the same product page, the same shop catalogue.
WordPress is measured without a page cache, and we check it is off before timing, because a page a cache can serve is served from the cache by either setup and does not measure the engine. Every number below is WordPress running PHP, the case that a cart, a search or a logged-in session always hits.
The servers
We used two Google Cloud servers that anyone can rent and check. The Intel
server is a 4-vCPU c2-standard-4 (Intel Xeon at 3.10 GHz,
2 physical cores with two threads each, 16 GB RAM). The
ARM server is a 4-vCPU c4a-standard-4 (Google Axion,
4 physical cores, 16 GB RAM). Both run Debian 12, and
BookPress is compiled the same way on both.
Read the two core counts before any number. "4 vCPU" is a different amount of hardware on each family, so we compare an ARM number only with a WordPress running on the same server.
The result: more requests a second, on both servers
We drove each engine to the most requests a second it serves with 99% of them under one second and none failing. On real store pages BookPress serves about 4.5 times the requests per second of the tuned WordPress on the Intel server and over 5 times on the ARM server. Every figure below is BookPress against WordPress on the same server.
| Page | Server | Requests / second | p50 response time | p99 response time |
|---|---|---|---|---|
| Elementor page | Intel | 4.53×162 against 36 rps | 3.80× | 1.93× |
| WooCommerce shop | Intel | 4.85×134 against 28 rps | 4.75× | 2.79× |
| Elementor page | ARM | 5.30×376 against 71 rps | 5.30× | 3.70× |
| WooCommerce shop | ARM | 5.19×297 against 57 rps | 5.20× | 2.50× |
Measured on Google Cloud c2-standard-4 (Intel) and c4a-standard-4 (Arm), uncached dynamic pages, BookPress 0.2.64 (the packaged build you install) against WordPress 7.1.3 / PHP 8.3.35 with nginx, PHP-FPM, Redis object cache, OPcache with JIT and MariaDB.
Requests per second is each engine at its knee; p50 and p99 are the median and 99th-percentile response-time multiples at WordPress's knee rung, the same concurrency for both. WordPress is measured without a page cache.
Store pages are mostly the plugin's own PHP, so they are the hardest case. Unlike a plugin-free page, they cannot be answered without running that PHP. BookPress runs it on its own PHP engine, which on these pages keeps up with PHP 8.3.35 and the JIT, or beats it. These pages used to be the weak case, and BookPress now leads on them.
A site with no plugins runs no PHP interpreter at all. There BookPress serves 112.9 times the requests per second of WordPress on the Intel server (5,234 against 46) and 125 times on the ARM server (11,436 against 91), with no plugins installed.
Page caches are a separate layer
A page cache serves stored HTML without rendering anything, on WordPress or on BookPress. A cache hit therefore measures neither engine. Each figure on this site is an uncached dynamic render on both stacks.
Some classic PHP themes. WordPress's own classic templates are lighter than its block themes. BookPress's classic-theme rendering is newer than its block path, and a few of the two-dozen bundled classic themes still fall back to an error today. The fix is on our roadmap. The store pages above are block themes.
Memory
Memory is a separate, earlier measurement, taken on BookPress 0.2.57. We measured it on both servers after a full load run, on the same site with all plugins active, counting memory shared between processes once.
Under load, four BookPress workers used about 0.6 GB. That is about the same as a right-sized WordPress (8 PHP children, 0.55 GB), which serves fewer pages, and a third of a tuned 64-child pool (1.8 GB). Thirty seconds after the load stopped, BookPress dropped to about 0.3 GB. WordPress held 0.43 GB (8 children) or 1.8 GB (64 children).
Workers load the engine code and plugin bytecode once and share it. Each additional worker adds its own working set under load and returns most of it when idle. A worker with no request for 30 seconds gives memory back to the system, so the idle figure falls. A WordPress pool holds what it preforked, busy or idle. The memory figures were taken on BookPress 0.2.57, 13 October 2026; the throughput run above is a later and separate measurement.
No object cache, no database server, no page cache
WordPress hosts assemble these tiers to keep PHP from doing work twice. Each object-cache read is a round trip to Redis and a decode in PHP. A database server is another round trip. A page cache stores a rendered copy so nginx can answer without entering the stack.
BookPress has none of them. Storage is embedded and in-process, so there is no round trip to save. There is no rendered copy to keep, because rendering the page from scratch is the fast path. A CDN is still worth having for the usual reasons: distance to your visitors, and static assets.
Each tier can be misconfigured, run out of memory, hold stale content, or need purging after a deploy. BookPress has none of these moving parts. That matters for operations first and for speed second.
One result goes against us. If a host already runs a Redis object cache, we leave it installed. Disabling it to improve our numbers would be dishonest. Our plugin engine activates the plugin and the site serves, but the plugin cannot do its job: BookPress's PHP engine does not provide the Redis client or the low-level network calls it needs. The plugin falls back to WordPress's per-request cache and stores nothing across requests. Activating any plugin means the site runs PHP for every request, so an active object cache makes a plugin-free page much slower and gives nothing in return. BookPress cannot run this plugin's function. That differs from not needing one. Do not install an object cache on BookPress. It costs you and gives you nothing.
What a page cache does, and what it cannot do
With a page cache in front of it, WordPress served tens of thousands of requests a second in this benchmark, far more than BookPress. The number is real. It is also nginx returning a file from disk, with no PHP running.
A page cache stops where its permission stops. It does not serve a cart, a checkout, an account page, anything carrying a session cookie, anything with a query string, or anything for a logged-in visitor. Those pages decide a store's capacity. On them the cache steps aside and the request reaches the PHP it stood in front of. Every figure on this page measures that case.
The WordPress we compared against, in full
It is WordPress 7.1.3 on PHP 8.3.35-FPM, tuned as a competent host tunes one: OPcache sized so nothing is evicted with the JIT on, a warm Redis object cache over a socket, MariaDB with a healthy buffer pool, and WooCommerce on its newer order storage (HPOS). We ran it in two pools so pool size does not skew the comparison: a tuned static 64 children pool and a right-sized dynamic, 8 children pool.
Exact configuration
- OPcache with the JIT on. 512 MB of compiled code, a 64 MB interned-strings buffer, a 100,000-file limit, timestamp validation off, and a 256 MB JIT buffer.
- A Redis object cache (Redis 7) over a UNIX socket, with the object-cache drop-in installed and the cache warm.
- MariaDB 11 with a 4 GB InnoDB buffer pool.
- PHP-FPM behind nginx 1.27. A static 64 children pool and a right-sized dynamic, 8 children pool, both measured.
- WooCommerce on HPOS, its newer order storage.
The plugins are the demo's own versions: WooCommerce 11.0.1, Elementor 4.2.3, Yoast SEO 28.3 and Contact Form 7 6.1.7, on the Kadence 1.5.2 theme. We time a page only after checking that WordPress and BookPress show the same page: the Elementor showcase, the product page and the shop catalogue, checked on both servers.
The BookPress configuration, to the same standard
bookpress --root /srv/sites/<site> --db /srv/sites/<site>/data/site.db \
--port <port> --workers 4 BookPress runs with no php.ini, no PHP-FPM pool, no object cache, no opcode cache, no page cache and no reverse proxy. Each BookPress number on this page is a page rendered from scratch.
Which server to rent
Rent the Arm server: four real cores where the Intel server has two, about 14 percent less on list price, and about 2.2 to 2.3 times the Elementor and WooCommerce requests per second on BookPress 0.2.64.
List price, Google Cloud us-central1 on-demand:
c4a-standard-4 $131.11 a month against
c2-standard-4 $152.43.
Hosting economics
A host sizes a server by memory. Under full load the same site took about 0.6 GB on four BookPress workers (measured on 0.2.57), against 0.55 GB for a right-sized WordPress and 1.8 GB for a tuned 64-child pool. When idle, BookPress gives memory back and the WordPress pools do not. We are measuring how many sites one machine carries.
We work out prices from the infrastructure a host stops paying for, which is what the numbers on this page measure. They run from $1.00€0.85 per site per month at Starter down to $0.45€0.38 at Agency, and per licensed vCPU above 500 sites. The pricing page lists the tiers and shows how the figure is worked out for your own fleet.