<?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: Alok Deep</title>
    <description>The latest articles on DEV Community by Alok Deep (@alok1663).</description>
    <link>https://dev.to/alok1663</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%2F4097920%2F13eb2106-9686-4250-8c70-e76401460e96.png</url>
      <title>DEV Community: Alok Deep</title>
      <link>https://dev.to/alok1663</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alok1663"/>
    <language>en</language>
    <item>
      <title>Redis vs. Memcached vs. Edge Caching: A 2026 Engineering Guide</title>
      <dc:creator>Alok Deep</dc:creator>
      <pubDate>Fri, 28 Aug 2026 06:33:20 +0000</pubDate>
      <link>https://dev.to/alok1663/redis-vs-memcached-vs-edge-caching-a-2026-engineering-guide-22f2</link>
      <guid>https://dev.to/alok1663/redis-vs-memcached-vs-edge-caching-a-2026-engineering-guide-22f2</guid>
      <description>&lt;p&gt;Over the past twenty-five years, caching architectures have evolved through three distinct generations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Generation 1 (Local In-Memory / Memcached):&lt;/strong&gt; Simple key-value byte caching on local servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation 2 (In-VPC In-Memory Databases / Redis):&lt;/strong&gt; Centralized clusters with rich data structures, persistence, and pub/sub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation 3 (Distributed Edge Caching Proxies / ApexCache):&lt;/strong&gt; Globally distributed reverse proxies with Change Data Capture (CDC) and SingleFlight request coalescing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each tool was designed for specific trade-offs. Here is an architectural breakdown of when to use Memcached, when to use Redis, and when to use an Edge Caching Gateway.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Memcached: The Raw Multi-Threaded Byte Cache
&lt;/h2&gt;

&lt;p&gt;Memcached was created in 2003 for LiveJournal. It is a multi-threaded, in-memory key-value cache designed to store raw string or binary blobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Memcached Wins:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Threaded Throughput:&lt;/strong&gt; Memcached utilizes multiple CPU cores efficiently on a single large instance (e.g. 64 vCPUs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity:&lt;/strong&gt; If you only need a raw LRU string cache without persistence, data structures, or replication overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where Memcached Falls Short:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No native persistence or replication failovers.&lt;/li&gt;
&lt;li&gt;No rich data structures (lists, sets, sorted sets).&lt;/li&gt;
&lt;li&gt;In-VPC only: Does not reduce network distance for global users.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Redis: The In-Memory Data Structure Store
&lt;/h2&gt;

&lt;p&gt;Redis, released in 2009, transformed backend engineering by introducing rich data structures and replication.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Redis Wins:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queues &amp;amp; Background Jobs:&lt;/strong&gt; BullMQ, Sidekiq, Celery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Pub/Sub &amp;amp; WebSockets:&lt;/strong&gt; Managing live event distribution across microservices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Locks &amp;amp; Counters:&lt;/strong&gt; &lt;code&gt;INCRBY&lt;/code&gt;, &lt;code&gt;Redlock&lt;/code&gt;, atomic rate limiting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geospatial &amp;amp; Leaderboards:&lt;/strong&gt; Sorted Sets (&lt;code&gt;ZSET&lt;/code&gt;) and Geo commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where Redis Falls Short:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Response Caching:&lt;/strong&gt; Requires extensive custom invalidation code and suffers from dual-write desync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-Region Latency:&lt;/strong&gt; Sits in your cloud VPC, adding 150ms–300ms of cellular latency for global mobile users.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Edge Caching Gateways (ApexCache): The Global HTTP Proxy
&lt;/h2&gt;

&lt;p&gt;ApexCache sits directly in the HTTP traffic path between client applications and your backend servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Edge Caching Wins:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accelerating REST &amp;amp; GraphQL APIs:&lt;/strong&gt; Drops response times to under 15ms globally without modifying backend application code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Database Invalidation:&lt;/strong&gt; Uses Change Data Capture (CDC) to purge cache tags directly on database commits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thundering Herd Protection:&lt;/strong&gt; SingleFlight coalesces thousands of concurrent misses into 1 origin query.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Complete Technology Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Memcached&lt;/th&gt;
&lt;th&gt;Redis&lt;/th&gt;
&lt;th&gt;ApexCache (Edge Proxy)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In-VPC Byte Cache&lt;/td&gt;
&lt;td&gt;In-VPC Data Structure Store&lt;/td&gt;
&lt;td&gt;Global API Edge Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Network Location&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Central VPC Subnet&lt;/td&gt;
&lt;td&gt;Central VPC Subnet&lt;/td&gt;
&lt;td&gt;Globally Distributed Edge PoPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Threading Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-threaded&lt;/td&gt;
&lt;td&gt;Single-threaded event loop&lt;/td&gt;
&lt;td&gt;Multi-threaded Lock-Free Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Structures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strings / Blobs only&lt;/td&gt;
&lt;td&gt;Strings, Hashes, Lists, Sets, ZSets&lt;/td&gt;
&lt;td&gt;Serialized HTTP JSON / GraphQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Invalidation Mechanism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual app &lt;code&gt;delete()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Manual app &lt;code&gt;DEL&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Real-Time Database CDC &amp;amp; Webhooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache Stampede Guard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Manual distributed locks&lt;/td&gt;
&lt;td&gt;Native SingleFlight coalescing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom client code&lt;/td&gt;
&lt;td&gt;Custom client code&lt;/td&gt;
&lt;td&gt;1 DNS CNAME record (Zero code)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Summary Recommendation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Memcached&lt;/strong&gt; if you have a legacy, high-concurrency raw byte caching workload inside a single VPC.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Redis&lt;/strong&gt; for stateful operations: job queues, rate limiters, session storage, and pub/sub.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;strong&gt;ApexCache&lt;/strong&gt; in front of your HTTP APIs to handle read traffic, eliminate database stampedes, and deliver sub-15ms response times to global users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Documentation &amp;amp; Guides:&lt;/strong&gt; &lt;a href="https://getapexcache.com/docs" rel="noopener noreferrer"&gt;getapexcache.com/docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redis</category>
      <category>memcached</category>
      <category>database</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why Your React Native FlatList Lags on Pagination (And How Edge SWR Fixes It)</title>
      <dc:creator>Alok Deep</dc:creator>
      <pubDate>Fri, 28 Aug 2026 04:24:09 +0000</pubDate>
      <link>https://dev.to/alok1663/why-your-react-native-flatlist-lags-on-pagination-and-how-edge-swr-fixes-it-2clb</link>
      <guid>https://dev.to/alok1663/why-your-react-native-flatlist-lags-on-pagination-and-how-edge-swr-fixes-it-2clb</guid>
      <description>&lt;p&gt;Every mobile developer has encountered this frustration when building infinite scroll feeds in React Native:&lt;/p&gt;

&lt;p&gt;The user scrolls down a product list or social feed. As they reach the bottom of page 1, &lt;code&gt;onEndReached&lt;/code&gt; triggers to fetch page 2. &lt;/p&gt;

&lt;p&gt;Over a mobile 4G or 5G connection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The API request takes 450ms to 900ms to resolve.&lt;/li&gt;
&lt;li&gt;The user hits the bottom of the list and stares at a blank space or loading spinner.&lt;/li&gt;
&lt;li&gt;The scroll momentum stutters, and the feed feels sluggish.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is why client-side mobile pagination struggles on cellular networks, and how handling cursor pagination at the edge eliminates scroll lag.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Cellular Latency Problem in Mobile Apps
&lt;/h2&gt;

&lt;p&gt;Mobile devices do not have continuous high-speed fiber connections. Over cellular networks (4G/LTE/5G), establishing network handshakes and traversing physical distance to a central cloud server introduces high latency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mobile Phone (Cellular Tower)
         │  (Radio access network latency: 60ms–150ms)
         ▼
Regional Internet Routing (2-4 hops)
         │  (Transit RTT: 80ms–200ms)
         ▼
Origin Data Center (us-east-1)
         │
         ├── App Server JSON Serialization (40ms)
         └── Database Offset / Cursor Query (80ms)
         │
         ▼
Total Request Time: 260ms – 570ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user scrolls quickly, the device cannot fetch pages fast enough to keep up with the scroll speed.&lt;/p&gt;




&lt;h2&gt;
  
  
  3 Fixes for Instant Mobile Pagination
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Cursor Normalization at the Edge
&lt;/h3&gt;

&lt;p&gt;Offset pagination (&lt;code&gt;?offset=40&amp;amp;limit=20&lt;/code&gt;) is slow on SQL databases because the database has to scan and discard 40 rows before returning the result.&lt;/p&gt;

&lt;p&gt;Use cursor-based pagination with indexed keys (&lt;code&gt;?cursor=item_9281&amp;amp;limit=20&lt;/code&gt;), and route the mobile app's API base URL through an edge proxy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// React Native API Client&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.your-app.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Routed via CNAME to ApexCache&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchFeedPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cursor&lt;/span&gt; 
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/v1/feed?cursor=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;limit=20`&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/v1/feed?limit=20`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Edge-Side Stale-While-Revalidate (SWR)
&lt;/h3&gt;

&lt;p&gt;Because page 1 and page 2 are requested frequently by all active users, the edge proxy caches the serialized JSON responses in memory at points of presence close to the user.&lt;/p&gt;

&lt;p&gt;When the mobile app requests &lt;code&gt;GET /v1/feed?cursor=item_9281&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The nearest edge node returns the cached JSON in &lt;strong&gt;under 14 milliseconds&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The network round-trip finishes before the user reaches the end of the current viewport.&lt;/li&gt;
&lt;li&gt;The FlatList renders the next 20 items seamlessly without any visible loading spinner.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Pre-Fetching Next Page During Scroll
&lt;/h3&gt;

&lt;p&gt;Combine edge caching with intelligent client-side prefetching. &lt;/p&gt;

&lt;p&gt;Instead of waiting for &lt;code&gt;onEndReached&lt;/code&gt; (which fires when the user is already at the bottom), trigger a background pre-fetch when the user scrolls past the 70% threshold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FlatList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ActivityIndicator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ProductFeed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nextCursor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNextCursor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loadMore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;nextCursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchFeedPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextCursor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nf"&gt;setNextCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextCursor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextCursor&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FlatList&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;keyExtractor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;renderItem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductCard&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="nx"&gt;onEndReached&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loadMore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onEndReachedThreshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Trigger early when half a screen away&lt;/span&gt;
      &lt;span class="nx"&gt;ListFooterComponent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ActivityIndicator&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;small&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Production Metrics
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Central Cloud Origin&lt;/th&gt;
&lt;th&gt;Edge Proxy (ApexCache)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P50 Page Fetch Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;420ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P99 Page Fetch Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,280ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scroll Stutters / Janks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frequent on fast scrolls&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Zero visible lag&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database Read IOPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% load&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8% load (92% offload)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Mobile pagination lag is primarily a network distance and database scan problem.&lt;/p&gt;

&lt;p&gt;By adopting cursor-based queries and offloading paginated reads to a compiled edge proxy, mobile feeds load instantly across 4G and 5G connections without overloading your database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation on Mobile API Caching:&lt;/strong&gt; &lt;a href="https://getapexcache.com/docs/integrate-mobile" rel="noopener noreferrer"&gt;getapexcache.com/docs/integrate-mobile&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>reactnative</category>
      <category>mobile</category>
      <category>performance</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stellate vs. ApexCache: Beyond GraphQL Caching</title>
      <dc:creator>Alok Deep</dc:creator>
      <pubDate>Fri, 28 Aug 2026 04:19:52 +0000</pubDate>
      <link>https://dev.to/alok1663/stellate-vs-apexcache-beyond-graphql-caching-140b</link>
      <guid>https://dev.to/alok1663/stellate-vs-apexcache-beyond-graphql-caching-140b</guid>
      <description>&lt;p&gt;GraphQL adoption has grown dramatically across modern web and mobile applications. As GraphQL backends scale, managing query complexity and resolver execution costs becomes a primary engineering challenge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stellate&lt;/strong&gt; (formerly GraphCDN) pioneered dedicated GraphQL edge caching, providing normalized caching and schema-aware invalidation for GraphQL endpoints.&lt;/p&gt;

&lt;p&gt;However, modern engineering backends are rarely pure GraphQL. In production, engineering stacks almost always operate a &lt;strong&gt;hybrid architecture&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL for complex frontend data trees&lt;/li&gt;
&lt;li&gt;REST endpoints for third-party integrations, mobile webhooks, and file uploads&lt;/li&gt;
&lt;li&gt;Internal microservices communicating via JSON over HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an architectural comparison between GraphQL-only caching proxies and unified edge gateways like &lt;strong&gt;ApexCache&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Unified REST + GraphQL Caching
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stellate:&lt;/strong&gt; Focuses exclusively on GraphQL APIs. If your stack includes REST endpoints (e.g. &lt;code&gt;/api/v1/auth&lt;/code&gt;, &lt;code&gt;/api/v1/webhooks&lt;/code&gt;, &lt;code&gt;/api/v1/products&lt;/code&gt;), you must maintain a separate caching and routing infrastructure for REST.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ApexCache:&lt;/strong&gt; Provides a &lt;strong&gt;unified edge gateway&lt;/strong&gt; supporting REST, GraphQL (AST body parsing &amp;amp; automatic query hashing), and microservice APIs under a single DNS hostname and control plane.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Invalidation: Mutation Sniffing vs. Real Database CDC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In Stellate:&lt;/strong&gt; Invalidation primarily relies on intercepting GraphQL &lt;code&gt;mutation&lt;/code&gt; operations returned through the proxy, or dispatching manual purge requests via the Stellate Invalidation API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In ApexCache:&lt;/strong&gt; In addition to mutation detection and webhook purges, ApexCache connects directly to your database transaction log (PostgreSQL WAL, MySQL binlog, MongoDB Change Streams) via Change Data Capture (CDC). Direct database updates (cron jobs, admin scripts, direct SQL migrations) automatically invalidate cache tags across global edge nodes in &lt;strong&gt;under 10ms&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Enterprise In-VPC &amp;amp; Air-Gapped Deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stellate:&lt;/strong&gt; Primarily hosted as a managed cloud SaaS platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ApexCache:&lt;/strong&gt; Offers both a global SaaS edge network and &lt;strong&gt;Enterprise In-VPC Self-Hosting&lt;/strong&gt;, allowing regulated healthcare, fintech, and government organizations to deploy air-gapped Docker proxy containers inside private AWS, GCP, or Azure VPCs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Feature Comparison: Stellate vs. ApexCache
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Stellate&lt;/th&gt;
&lt;th&gt;ApexCache&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Protocol Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GraphQL only&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Unified REST, GraphQL &amp;amp; Microservices&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Request Coalescing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (GraphQL)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes (SingleFlight across REST &amp;amp; GraphQL)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database Sync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual Purge API &amp;amp; Mutations&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Real-Time Database CDC (PostgreSQL, MySQL, Mongo)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;In-VPC Self-Hosting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited / Enterprise Cloud&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Full Air-Gapped In-VPC Docker Deployment&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Developer Tier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Usage-based tier&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100,000 requests/month free on Developer tier&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If your application architecture is 100% GraphQL and you only require managed cloud caching, Stellate provides a dedicated GraphQL solution.&lt;/p&gt;

&lt;p&gt;If your backend is a hybrid environment utilizing both REST and GraphQL, or if you require &lt;strong&gt;direct database CDC invalidation&lt;/strong&gt; and &lt;strong&gt;self-hosted In-VPC deployment options&lt;/strong&gt;, ApexCache provides a unified, higher-throughput edge infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation &amp;amp; Setup:&lt;/strong&gt; &lt;a href="https://getapexcache.com/docs/vs-stellate" rel="noopener noreferrer"&gt;getapexcache.com/docs/vs-stellate&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>api</category>
      <category>architecture</category>
      <category>performance</category>
    </item>
    <item>
      <title>Anatomy of a 1ms API Response: Breaking Down Network and Gateway Overheads</title>
      <dc:creator>Alok Deep</dc:creator>
      <pubDate>Fri, 28 Aug 2026 04:06:46 +0000</pubDate>
      <link>https://dev.to/alok1663/anatomy-of-a-1ms-api-response-breaking-down-network-and-gateway-overheads-pja</link>
      <guid>https://dev.to/alok1663/anatomy-of-a-1ms-api-response-breaking-down-network-and-gateway-overheads-pja</guid>
      <description>&lt;p&gt;What actually happens inside the operating system, network stack, and reverse proxy when an API returns a response in &lt;strong&gt;under 1 millisecond&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;When benchmarking low-latency systems, software overhead is often dwarfed by network and operating system mechanics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCP handshake and TLS 1.3 key exchange&lt;/li&gt;
&lt;li&gt;Kernel socket buffer allocations and zero-copy transfers&lt;/li&gt;
&lt;li&gt;Memory cache lookup and hash table lock contention&lt;/li&gt;
&lt;li&gt;HTTP/2 and HTTP/3 multiplexing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an engineering breakdown of where latency goes during an HTTP request, and how compiled native reverse proxies optimize every stage of the pipeline to deliver sub-millisecond gateway performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Request Lifecycle Timeline (Step-by-Step)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time (µs)    Stage Description
0 µs         Client Socket sends HTTP GET request over existing TCP/TLS connection
120 µs       Kernel receives packets -&amp;gt; epoll/kqueue wakes up proxy event loop
220 µs       Zero-copy socket read into pre-allocated memory buffer
340 µs       HTTP parser parses headers &amp;amp; URI (SIMD-accelerated)
410 µs       Hasher computes aHash of cache key -&amp;gt; Look up in Sharded Cache Map
480 µs       Cache HIT -&amp;gt; Retrieve pointer to cached response byte slice
580 µs       Assemble HTTP response frame (HTTP/2 HEADERS + DATA frame)
720 µs       Write response bytes to kernel TCP socket buffer via writev / sendfile
850 µs       Packets leave network interface card (NIC)
Total Gateway Overhead: ~850 microseconds (0.85ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4 Engineering Techniques for Sub-Millisecond Gateways
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. SIMD-Accelerated HTTP Header Parsing
&lt;/h3&gt;

&lt;p&gt;Traditional string manipulation in standard HTTP parsers scans character-by-character.&lt;/p&gt;

&lt;p&gt;Modern native proxy engines use Single Instruction, Multiple Data (SIMD) CPU instructions (AVX2 on x86-64, NEON on ARM64) to parse 16 to 32 bytes of HTTP headers per CPU cycle. Validating header boundaries (&lt;code&gt;\r\n&lt;/code&gt;) and URI paths takes less than 80 nanoseconds.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Lock-Free Sharded In-Memory Caches
&lt;/h3&gt;

&lt;p&gt;If all worker threads read and write to a single global hash map protected by a mutex, CPU cores spend 40% of their cycles waiting for lock acquisition under 50,000 requests per second.&lt;/p&gt;

&lt;p&gt;ApexCache uses &lt;strong&gt;sharded concurrent hash tables&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keys are partitioned across 128 independent memory shards.&lt;/li&gt;
&lt;li&gt;Read operations use atomic reference counting (zero mutex locks).&lt;/li&gt;
&lt;li&gt;Multiple CPU cores read cached payloads simultaneously without thread contention.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Pre-Allocated Slab Memory Buffers (Zero GC Jitter)
&lt;/h3&gt;

&lt;p&gt;In garbage-collected languages (Go, Java, Node.js), allocating buffers for incoming requests creates memory churn that triggers garbage collection sweeps.&lt;/p&gt;

&lt;p&gt;Native compiled proxies pre-allocate slabs of fixed-size memory buffers at boot time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a request arrives, a buffer is checked out from the pool.&lt;/li&gt;
&lt;li&gt;When the response is flushed to the socket, the buffer is recycled back into the pool.&lt;/li&gt;
&lt;li&gt;Memory usage remains flat, and garbage-collection pauses are completely eliminated.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Zero-Copy Socket Transfers with &lt;code&gt;writev&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of copying response header strings and response body bytes into a new intermediate buffer before writing to the network socket, the proxy uses the &lt;code&gt;writev&lt;/code&gt; system call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gathering write: passes memory pointers directly to kernel&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;iovec&lt;/span&gt; &lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iov_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iov_len&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iov_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cached_body_bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iov_len&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;writev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operating system reads the data directly from application memory into network packet buffers with zero intermediate copies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark Results: 100,000 Requests/Sec
&lt;/h2&gt;

&lt;p&gt;Here is a &lt;code&gt;wrk&lt;/code&gt; benchmark measuring gateway overhead on a 4-core AWS Graviton3 instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wrk &lt;span class="nt"&gt;-t4&lt;/span&gt; &lt;span class="nt"&gt;-c1000&lt;/span&gt; &lt;span class="nt"&gt;-d30s&lt;/span&gt; http://127.0.0.1:8080/api/v1/ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Latency Percentile&lt;/th&gt;
&lt;th&gt;Measured Proxy Overhead&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P50 Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.24ms (240 microseconds)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P90 Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.48ms (480 microseconds)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P99 Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.82ms (820 microseconds)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max Latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.24ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;94,200 req/sec&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Sub-millisecond API response times are achieved by eliminating runtime garbage collection, avoiding lock contention on concurrent hash maps, and passing memory pointers directly to kernel network buffers.&lt;/p&gt;

&lt;p&gt;When gateway overhead is under 1ms, total API response time is determined solely by the speed of light to the user's nearest regional edge node.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation &amp;amp; Benchmarks:&lt;/strong&gt; &lt;a href="https://getapexcache.com/docs" rel="noopener noreferrer"&gt;getapexcache.com/docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>performance</category>
      <category>networking</category>
      <category>systems</category>
      <category>backend</category>
    </item>
    <item>
      <title>Building a Zero-Downtime Cache Invalidation Pipeline with Webhooks</title>
      <dc:creator>Alok Deep</dc:creator>
      <pubDate>Fri, 28 Aug 2026 04:00:57 +0000</pubDate>
      <link>https://dev.to/alok1663/building-a-zero-downtime-cache-invalidation-pipeline-with-webhooks-4m8d</link>
      <guid>https://dev.to/alok1663/building-a-zero-downtime-cache-invalidation-pipeline-with-webhooks-4m8d</guid>
      <description>&lt;p&gt;Cache invalidation is notoriously difficult to get right in high-throughput systems.&lt;/p&gt;

&lt;p&gt;If your cache TTL is too short (e.g. 10 seconds), your database gets overwhelmed by stampedes. If your TTL is too long (e.g. 24 hours), your application serves stale data after updates.&lt;/p&gt;

&lt;p&gt;The standard solution is &lt;strong&gt;event-driven cache invalidation&lt;/strong&gt;. Whenever a mutation occurs in your CMS, e-commerce admin, or custom backend, you trigger an invalidation webhook that purges matching cache entries across all edge points of presence.&lt;/p&gt;

&lt;p&gt;Here is how to design a resilient, zero-downtime cache invalidation pipeline with surrogate key tags, fanout workers, and retry guarantees.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Surrogate Key Tags (The Tagging Hierarchy)
&lt;/h2&gt;

&lt;p&gt;URL-based invalidation (&lt;code&gt;PURGE /api/products/linen-shirt&lt;/code&gt;) is brittle because a single product update might affect dozens of related endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The product details page (&lt;code&gt;/api/products/linen-shirt&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The category listing (&lt;code&gt;/api/collections/summer-apparel&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The brand page (&lt;code&gt;/api/brands/linen-co&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The search index and homepage featured carousel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of tracking every possible URL, attach &lt;strong&gt;surrogate key tags&lt;/strong&gt; to your HTTP responses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;X-ApexCache-Tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product:1029, collection:summer, brand:42, catalog&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The edge proxy indexes these tags in an in-memory inverted index. When a purge request arrives for &lt;code&gt;product:1029&lt;/code&gt;, the proxy instantly evicts every cached response containing that tag across the cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Invalidation Webhook Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Admin / CMS Mutation ──► Database Commit ──► Event Emitter (Webhook Dispatcher)
                                                   │
                                                   ▼
                                      ApexCache Invalidation API
                                                   │
                                    (Parallel Distributed Fanout)
                                                   ├── Edge PoP (US-East): Purged in 6ms
                                                   ├── Edge PoP (EU-West): Purged in 8ms
                                                   └── Edge PoP (AP-South): Purged in 9ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Implementation in Node.js / TypeScript
&lt;/h2&gt;

&lt;p&gt;Here is a resilient webhook dispatcher implementing non-blocking dispatch with exponential backoff retries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// services/cache-invalidator.ts&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;InvalidateOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;invalidateEdgeCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InvalidateOptions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APEXCACHE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.getapexcache.com/api/v1/cache/invalidate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;maxRetries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Purge successful&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[ApexCache] Invalidation returned status &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Retrying...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[ApexCache] Network error during purge attempt &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Exponential backoff: 50ms, 100ms, 200ms&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[ApexCache] Failed to invalidate cache after max retries:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Hooking Into ORMs (Prisma / Drizzle / TypeORM)
&lt;/h2&gt;

&lt;p&gt;Integrate the invalidation dispatcher directly into your database middleware or lifecycle hooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prisma Middleware Example&lt;/span&gt;
&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Check if the action was a mutation&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updateMany&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// Fire-and-forget background eviction&lt;/span&gt;
      &lt;span class="nf"&gt;invalidateEdgeCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`product:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;catalog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Latency and Consistency Guarantees
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purge Execution Time:&lt;/strong&gt; Tag evictions complete across global edge nodes in &lt;strong&gt;6ms to 12ms&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Downtime:&lt;/strong&gt; While tags are being evicted, the proxy handles in-flight requests seamlessly without returning 502/504 errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thundering Herd Shield:&lt;/strong&gt; The next incoming request for the evicted tag triggers a single coalesced origin fetch via SingleFlight, preventing database spikes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a zero-downtime cache invalidation pipeline requires separating cache tags from raw URLs and dispatching event-driven purges on database commits.&lt;/p&gt;

&lt;p&gt;With tag-based surrogate keys and fast webhook dispatch, you can maintain long cache TTLs (24+ hours) while guaranteeing that updates reflect globally within milliseconds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation &amp;amp; API Reference:&lt;/strong&gt; &lt;a href="https://getapexcache.com/docs/invalidation" rel="noopener noreferrer"&gt;getapexcache.com/docs/invalidation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>architecture</category>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
