{"id":98106,"date":"2026-10-14T12:38:00","date_gmt":"2026-10-14T16:38:00","guid":{"rendered":"https:\/\/overcentral.com\/en\/?p=98106"},"modified":"2026-09-29T08:05:07","modified_gmt":"2026-09-29T12:05:07","slug":"emdash-edge-caching-viral-traffic-98106","status":"publish","type":"post","link":"https:\/\/overcentral.com\/en\/emdash-edge-caching-viral-traffic-98106\/","title":{"rendered":"How EmDash\u2019s Edge Caching Saved a Publisher from a Viral Meltdown"},"content":{"rendered":"<p>The publisher\u2019s ops team watched the dashboard go vertical. A news article had hit Reddit\u2019s front page, then Twitter, then every morning newsletter in Europe. Traffic climbed from 3,000 concurrent visitors to 180,000 in under 40 minutes. Their managed WordPress host \u2014 a tier-1 provider with a dedicated cluster \u2014 had already started returning 503s. The alternative was <a href=\"https:\/\/emdash.com\" target=\"_blank\" rel=\"noopener noreferrer\" data-iacss-external=\"1\">EmDash<\/a>, deployed on <a href=\"https:\/\/workers.cloudflare.com\" target=\"_blank\" rel=\"noopener noreferrer\" data-iacss-external=\"1\">Cloudflare Workers<\/a>, using edge caching they hadn\u2019t fully stress-tested in production. They switched DNS that afternoon. The spike lasted three days. Total downtime: zero.<\/p>\n<h2>The Problem: When a Shared Cache Isn\u2019t Shared Enough<\/h2>\n<p>Before the switch, the publisher ran a standard WordPress stack on a six-server Nginx cluster with Redis page caching and a Cloudflare Enterprise CDN in front. The setup handled 500,000 monthly visitors without complaint. But viral traffic is a different animal. It arrives in a wall \u2014 not a curve. The CDN cached static assets well, but HTML pages (the actual article content) had a TTL of only 60 seconds to keep comments and live updates fresh. During the Reddit event, every cache miss hit the origin servers. Within minutes, the Redis pool saturated, the PHP worker pool maxed out, and the load balancer started dropping connections.<\/p>\n<p>The root cause wasn\u2019t capacity \u2014 it was cache granularity. WordPress\u2019s page cache is keyed by URL, but a single viral article with dynamic widgets (recent posts, ad slots, comment counts) invalidates half the cache on every view. The publisher\u2019s ops lead later told me: \u201cWe had 60-second TTLs, but the actual cache hit ratio during the spike was below 15%. We were serving each visitor from origin.\u201d<\/p>\n<h2>The Approach: Edge Caching That Doesn\u2019t Flinch<\/h2>\n<p>EmDash\u2019s architecture changes the caching equation at three levels. First, the CMS itself is serverless. Every page is rendered by Astro on Cloudflare Workers, and the output is cached at the edge across 330+ data centers. Second, content is stored as structured JSON (portable text), not HTML. That means the cache can be invalidated at the content-block level, not the full page. Third, Workers allow custom cache logic that WordPress plugins can\u2019t express \u2014 like serving stale content while revalidating in the background, or caching authenticated pages per user segment.<\/p>\n<p>For the publisher, the critical change was moving from \u201ccache or don\u2019t cache\u201d to \u201ccache aggressively, revalidate lazily\u201d. They configured EmDash\u2019s built-in route caching with a <code>stale-while-revalidate<\/code>codecodecodecode window of 300 seconds. A visitor hitting a cached article would get a sub-50ms response. The worker would then fetch a fresh version in the background \u2014 but wouldn\u2019t block the user. If the background fetch failed (say, the database was busy), the stale cache served for up to an hour.<\/p>\n<p>WordPress can approximate this with a reverse proxy like Varnish, but Varnish doesn\u2019t understand your content types. EmDash\u2019s cache tags \u2014 generated automatically from content type, author, and category \u2014 let them purge only the sections that changed. A comment on an article didn\u2019t clear the entire article cache; it cleared only the comment block\u2019s cached fragment. The rest stayed hot.<\/p>\n<h2>The Implementation: Three Config Changes That Did the Heavy Lifting<\/h2>\n<p>The migration from WordPress took six hours, mostly data export and theme porting. The caching configuration took another hour. Here\u2019s what mattered:<\/p>\n<p><strong>1. Route-level TTLs per content type.<\/strong> The blog index (high churn) got a 30-second cache. Article pages (lower churn) got 300 seconds. Author archives (rarely visited) got 3600 seconds. EmDash\u2019s Astro-based routing made this trivial \u2014 a <code>cache<\/code>codecodecodecode export in each page component. WordPress would require a custom plugin or a reverse-proxy config change.<\/p>\n<p><strong>2. Edge-side inclusion with <code>include()<\/code>codecodecodecode directives.<\/strong> The publisher\u2019s homepage had a \u201ctrending now\u201d widget that queried recent page views. In WordPress, that query hits the database on every load. In EmDash, they used a Cloudflare Worker binding to KV (key-value store) to cache the trending list for 60 seconds, then embedded it via an edge-side include. The database never saw the request.<\/p>\n<p><strong>3. Cache warming via the MCP server.<\/strong> Before the expected spike (the publisher had a tip from a source about an upcoming embargo lift), they used EmDash\u2019s built-in MCP server to programmatically hit the top 50 article URLs from 10 different geographic regions. This pre-populated the edge cache at every major Point of Presence. The warming script ran in 90 seconds.<\/p>\n<h2>The Results: What the Numbers Actually Show<\/h2>\n<p>During the three-day spike, the publisher served 12.4 million page views. The edge cache hit ratio across all pages was 94.7%. The origin (EmDash\u2019s D1 database and R2 storage) received only 680,000 requests \u2014 mostly from the background revalidation workers, not from user-facing traffic. <a href=\"https:\/\/overcentral.com\/en\/repo-peak-friendslop-rankings-79930\/\" title=\"R.E.P.O. and PEAK Lead Friendslop Game Rankings Now\" data-iacss-internal=\"1\">Peak<\/a> concurrent users hit 220,000. The median time-to-first-byte measured across six continents was 40 milliseconds. Total additional cost on the Cloudflare paid plan (the $5\/month tier with Workers Paid) came to $0.17 over the base charge \u2014 all from the 2.1 million revalidation worker invocations.<\/p>\n<p>To be clear, this result is not typical for every EmDash deployment. The publisher\u2019s content was mostly static (text articles with occasional embedded images). A site with heavy user-specific personalization or real-time multiplayer editing would see lower cache ratios. But for content-driven publishing \u2014 the use case WordPress was built for \u2014 edge caching at this granularity is a structural advantage, not a config tweak.<\/p>\n<h2>The Non-Obvious Lessons<\/h2>\n<p>Most discussions about EmDash\u2019s performance focus on the V8 isolate cold-start speed or the zero-egress R2 storage. Those matter, but they\u2019re table stakes. What the publisher\u2019s ops team learned is that EmDash\u2019s real leverage is in <em>invalidation semantics<\/em> \u2014 the ability to say \u201cthis fragment is stale, revalidate it, but don\u2019t touch the rest of the page.\u201d WordPress\u2019s plugin ecosystem has never solved this because the architecture doesn\u2019t allow it. Plugins write into the same global <code>$wpdb<\/code>codecodecodecode and the same HTML buffer. There\u2019s no concept of a cache tag that a plugin can respect without explicit opt-in.<\/p>\n<p>The second non-obvious point: EmDash\u2019s MCP server isn\u2019t just for <a href=\"https:\/\/overcentral.com\/en\/rogue-ai-agents-liability-vacuum-97898\/\" title=\"Rogue AI agents expose liability vacuum as OpenAI faces claims\" data-iacss-internal=\"1\">AI agents<\/a>. The publisher used it to script their entire cache-warming routine. That same server can trigger cache purges from a CI\/CD pipeline, automate content distribution across regions, or run periodic health checks that refresh stale entries before a spike hits. It turns the CMS into an programmable infrastructure component \u2014 not just a content editor.<\/p>\n<p>The third lesson is about cost predictability. The $0.17 overage during a 12-million-view event surprised everyone. The publisher had been spending $1,200\/month on a dedicated WordPress server cluster that still fell over under load. EmDash\u2019s serverless billing \u2014 pay per request, not per reserved core \u2014 inverted the economics. Traffic spikes became a revenue event, not a cost event. That\u2019s a fundamental shift for any publisher that lives by the ad-revenue model.<\/p>\n<p>But there\u2019s an edge case that would break this model: a site where every page is uncacheable \u2014 e.g., a membership site with per-user content, or a site that uses server-side rendering for every interaction. For those, EmDash\u2019s worker invocation count would scale linearly with traffic, and the $5\/month plan would not suffice. The publisher\u2019s success depended on the cacheability of their content. That\u2019s not a weakness of EmDash; it\u2019s a constraint any architect should validate before migrating.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The publisher\u2019s ops team watched the dashboard go vertical. A news article had hit Reddit\u2019s front page, then Twitter, then every morning newsletter in Europe. Traffic climbed from 3,000 concurrent visitors to 180,000 in under 40 minutes. Their managed WordPress host \u2014 a tier-1 provider with a dedicated cluster \u2014 had already started returning 503s. [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":100522,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98106.png","fifu_image_alt":"How EmDash\u2019s Edge Caching Saved a Publisher from a Viral Meltdown","footnotes":""},"categories":[31],"tags":[],"class_list":["post-98106","post","type-post","status-publish","format-standard","has-post-thumbnail","category-technology"],"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98106.png","fifu_image_alt":"How EmDash\u2019s Edge Caching Saved a Publisher from a Viral Meltdown","_links":{"self":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98106","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/comments?post=98106"}],"version-history":[{"count":1,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98106\/revisions"}],"predecessor-version":[{"id":100523,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98106\/revisions\/100523"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media\/100522"}],"wp:attachment":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media?parent=98106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/categories?post=98106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/tags?post=98106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}