<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: HostlessWP</title>
    <description>The latest articles on DEV Community by HostlessWP (@hostlesswp).</description>
    <link>https://dev.to/hostlesswp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4194106%2Fd03d3cb2-2a32-450d-9c66-76c66217c948.png</url>
      <title>DEV Community: HostlessWP</title>
      <link>https://dev.to/hostlesswp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hostlesswp"/>
    <language>en</language>
    <item>
      <title>What we learned running WordPress on Cloudflare Workers</title>
      <dc:creator>HostlessWP</dc:creator>
      <pubDate>Mon, 19 Oct 2026 12:17:25 +0000</pubDate>
      <link>https://dev.to/hostlesswp/what-we-learned-running-wordpress-on-cloudflare-workers-4f1f</link>
      <guid>https://dev.to/hostlesswp/what-we-learned-running-wordpress-on-cloudflare-workers-4f1f</guid>
      <description>&lt;p&gt;The usual answer to "can WordPress run on Cloudflare?" is no: Workers run JavaScript and WebAssembly, WordPress needs PHP and MySQL, so you either export a static copy or keep a server. That answer is out of date. The WordPress Playground project builds PHP for WebAssembly, and that build runs inside a Worker.&lt;/p&gt;

&lt;p&gt;We maintain &lt;a href="https://github.com/hostlesswp/hostlesswp" rel="noopener noreferrer"&gt;HostlessWP&lt;/a&gt;, an open source tool (GPL-2.0) that uses it to move an existing WordPress site onto Workers: &lt;code&gt;npx hostlesswp&lt;/code&gt; reads &lt;code&gt;wp-config.php&lt;/code&gt;, runs WordPress core, the theme and the plugins in php-wasm (PHP 8.3), reaches the site's existing MySQL database through Hyperdrive, and puts the media library in R2 or any S3-compatible bucket. These are the things that decided whether it was usable, with the numbers we measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Placement matters more than anything else
&lt;/h2&gt;

&lt;p&gt;WordPress sends its queries one after another. A core home page made 29 queries in our tests, a WooCommerce home page 74. Every one of them waits for a round trip to the database.&lt;/p&gt;

&lt;p&gt;With the database in US East (Virginia) and requests entering Cloudflare in Singapore, a Worker with default placement runs near the visitor, so every query crosses the Pacific:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Per query&lt;/th&gt;
&lt;th&gt;Core home page&lt;/th&gt;
&lt;th&gt;WooCommerce home page&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Worker near the visitor (Singapore)&lt;/td&gt;
&lt;td&gt;~230 ms&lt;/td&gt;
&lt;td&gt;7.7 s&lt;/td&gt;
&lt;td&gt;19.6 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker next to the database (&lt;code&gt;placement.region = "aws:us-east-1"&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;~33 ms&lt;/td&gt;
&lt;td&gt;1.2 to 1.3 s&lt;/td&gt;
&lt;td&gt;2.9 to 3.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Next to the database, direct TCP instead of Hyperdrive (not shipped)&lt;/td&gt;
&lt;td&gt;~2 ms&lt;/td&gt;
&lt;td&gt;0.07 s&lt;/td&gt;
&lt;td&gt;0.19 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;PHP processing time per page, warm requests, including database waits; medians of 1 to 5 samples per cell, so read them as orders of magnitude. Pinning the Worker next to the database made pages about six times faster, which is why the tool looks up where the database is and sets &lt;code&gt;placement.region&lt;/code&gt; automatically.&lt;/p&gt;

&lt;p&gt;Pages for logged-out visitors come from a page cache in Workers KV and do not start PHP at all, so these numbers are what logged-in users, the admin and uncached pages see.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Hyperdrive adds about 30 ms per query, and it does not keep sessions
&lt;/h2&gt;

&lt;p&gt;Inside the same Worker invocation, a direct &lt;code&gt;SELECT 1&lt;/code&gt; took about 2 ms and opening the connection 2 to 7 ms, against about 33 ms through Hyperdrive. We could not tell how much of that is the distance to Hyperdrive's pool and how much is its own processing. The direct path is not shipped yet because the test database used a private certificate authority that the Workers TLS client does not accept.&lt;/p&gt;

&lt;p&gt;The less obvious part: Hyperdrive may run consecutive statements on different server connections. Anything WordPress or a plugin sets with &lt;code&gt;SET&lt;/code&gt; for the session can be gone on the next query. We carry session state per statement with &lt;code&gt;SET_VAR&lt;/code&gt; hints, answer &lt;code&gt;SELECT @@var&lt;/code&gt; from &lt;code&gt;SHOW VARIABLES&lt;/code&gt;, and run &lt;code&gt;SQL_CALC_FOUND_ROWS&lt;/code&gt; paging as a parallel &lt;code&gt;COUNT&lt;/code&gt;. That last change took the REST posts list from about 2.5 s to 1.6 s.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The clock does not move while you compute
&lt;/h2&gt;

&lt;p&gt;Workers freeze the clock during CPU work. PHP code that loops until the time changes, &lt;code&gt;uniqid()&lt;/code&gt; for example, spins forever. The fix is a clock that is strictly monotonic: every read returns a slightly later time than the previous one.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. OPcache is off in php-wasm unless you turn it on
&lt;/h2&gt;

&lt;p&gt;php-wasm's OPcache does not start by default because its SAPI is not on OPcache's whitelist. Patching that, putting OPcache in shared memory and mounting precompiled scripts makes a large difference for a code base the size of WordPress plus WooCommerce.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. What does not work yet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PHP &lt;code&gt;mail()&lt;/code&gt;. Use a mail plugin that sends over an HTTP API.&lt;/li&gt;
&lt;li&gt;Installing or updating plugins from the admin. You change them on the source site and redeploy.&lt;/li&gt;
&lt;li&gt;Multisite.&lt;/li&gt;
&lt;li&gt;Object cache drop-ins such as Redis are left out; WordPress uses its built-in cache.&lt;/li&gt;
&lt;li&gt;Imagick; images are processed with GD.&lt;/li&gt;
&lt;li&gt;Placement next to the database caused more cold starts (11 to 16 in 25 sequential requests, against 0 with default placement). We do not know why yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 30 most-installed plugins on WordPress.org loaded and worked at page level, and WooCommerce checkout, the Elementor editor and Yoast sitemaps were tested end to end. The per-plugin results are in the &lt;a href="https://hostlesswp.com/compatibility" rel="noopener noreferrer"&gt;compatibility table&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hostlesswp check   &lt;span class="c"&gt;# read-only compatibility report, changes nothing&lt;/span&gt;
npx hostlesswp         &lt;span class="c"&gt;# guided setup and deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your current site is not changed, and it keeps serving until you move the domain. There is a public WooCommerce demo running this way at &lt;a href="https://hostlesswp-demo.qc2uyes.workers.dev" rel="noopener noreferrer"&gt;https://hostlesswp-demo.qc2uyes.workers.dev&lt;/a&gt; (log in with demo / demo, it resets every 3 hours). Full method and numbers: &lt;a href="https://hostlesswp.com/benchmarks" rel="noopener noreferrer"&gt;https://hostlesswp.com/benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is an early preview (v0.1). If you run it on your own site, we would like to see your numbers.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>cloudflare</category>
      <category>webassembly</category>
      <category>php</category>
    </item>
  </channel>
</rss>
