<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Matthias Wilhelm - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Matthias Wilhelm - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/search-labs/author/matthias-wilhelm</link>
    </image>
    <link>https://www.elastic.co/search-labs/author/matthias-wilhelm</link>
    <atom:link href="https://www.elastic.co/search-labs/rss/author/matthias-wilhelm.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Sat, 10 Oct 2026 23:55:19 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Kibana cuts dashboard load time by up to 25% - here's the polling strategy behind it]]></title>
    <description><![CDATA[Find out how Kibana uses continuous polling and browser-side HTTP/2 detection to cut dashboard load times by up to 25%, with automatic fallback on HTTP/1.]]></description>
    <content:encoded><![CDATA[<p>Kibana dashboards and Discover now load up to 25% faster thanks to continuous polling. Instead of sleeping between periodic checks, Kibana now keeps HTTP connections open and delivers Elasticsearch query results the moment they're ready. On HTTP/2+ (the Kibana default since 9.0) this kicks in automatically with no configuration required. On HTTP/1, Kibana falls back to traditional polling to prevent connection pool exhaustion.</p><h2>How Kibana fetches data when loading a dashboard</h2><p>When a Dashboard is opened, most of the panels (internally, we call these <em>embeddables</em>) kick off one or more Elasticsearch queries. But instead of the simple call-and-response of a synchronous (sync) search, we use the power of asynchronous (async) search (<a href="https://www.elastic.co/docs/solutions/search/async-search-api">docs</a>).</p><p>With async search, query results are kept available in Elasticsearch outside of any particular HTTP request. This is important because it</p><ul><li><p>makes data loading resilient to network turbulence</p></li><li><p>powers our <a href="https://www.elastic.co/docs/explore-analyze/discover/background-search">background search feature</a> which allows users to work on other things in Kibana while they wait for a long-running dashboard or Discover session</p></li></ul><p>After the initial query is submitted, Kibana monitors the search to detect when it is complete and retrieve the result set.</p><h3>How traditional polling affects Kibana dashboard load times</h3><p>In traditional polling, Kibana submits a query, closes the initial connection, then periodically checks Elasticsearch for completion.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt093ed1a718d2f2ed/6a1710c28b73cb568118a109/2f44064a2e627866e129eb626f68ddd62230a4e2-1999x719.png" alt="Diagram showing traditional polling in Kibana. The Kibana timeline shows a short connection-open period after query submission, followed by a long sleeping period, then a brief poll for status, then results delivered. The Elasticsearch timeline runs a query that completes midway through Kibana's sleep period, illustrating the coordination gap that causes lost time." /><p>We do give Elasticsearch a short amount of time after query submission to simply complete the search and return results. If the search completes that quickly, it amounts to a simple call-and-response. But for longer searches, the initial connection is closed and Kibana begins periodically checking the search for completion. This is called <em>polling</em>.</p><h4>Performance drawbacks of traditional polling</h4><p>Looking at the figure above, perhaps you can already see the performance drawback to this approach: the search is most likely to finish during one of Kibana’s sleep intervals, leading to lost time.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3685326f1aa90a1b/6a1710c30c4857892b01ab7a/ad8b80d9e8d6d774065d62e352aad47c3ddb4686-1999x719.png" alt="Timeline diagram showing the performance cost of traditional polling. The Kibana timeline shows a connection-open period, a long sleep period, a poll for status, then results delivered. The Elasticsearch timeline shows the query completing midway through Kibana's sleep, followed by a red lost-time segment - the wasted duration before Kibana wakes up and retrieves the results." /><p>In the worst case scenario (when a search completes at the beginning of a sleep period) the entire duration of the polling interval will be wasted.</p><h4>The impact of a backoff strategy</h4><p>It’s standard practice when polling to apply a backoff strategy. This means that the longer the duration of the search, the less frequently we poll.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt37fb76cf22647ee5/6a1710c5a929cf6fcaae0abd/77665de4a0fd166b533a2c2c55f6f28e38cf37ce-1200x338.png" alt="Horizontal bar chart showing Kibana's polling interval backoff schedule by query duration. Queries under 1.5 seconds use an interval of roughly 0.5 seconds; 1.5–5 second queries use 1 second; 5–20 second queries use approximately 2.5 seconds; queries over 20 seconds use a 5-second polling interval." /><p>However, this also means that the potential lost time scales with the duration of the search.</p><h4>How polling intervals create sawtooth latency patterns</h4><p>Putting these factors together, our lost time becomes a stepwise sawtooth function.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4e81306b0c9f259/6a1710c147d49c34c42d8aec/d5cd43366f62de628c3a054ffb7bf0b05d7a1390-1500x600.png" alt="Line chart showing lost time in seconds versus query completion time in seconds, forming a sawtooth pattern where lost time rises then drops to zero repeatedly, with peaks growing from under 1 second to 5 seconds as query duration increases from 0 to 30 seconds." /><p>Here, the peaks are worst-case scenarios and the troughs are best case scenarios. This illustrates that traditional polling costs us between nothing and the full duration of the polling interval, depending on the search duration (and network conditions).</p><h2>Continuous polling: how Kibana eliminates wait time</h2><p>The problem with traditional polling is a fundamental lack of coordination between Kibana and Elasticsearch. Ideally, Kibana knows immediately when results are available. So, what if we inverted the polling pattern to where nearly all of the time is spent checking Elasticsearch and no time is spent sleeping?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4566eaaec79150c7/6a1710c78b73cb1df318a10d/7edc138528dfe1310df42f393ee7279fe3c4703b-1999x713.png" alt="Timeline diagram showing continuous polling in Kibana. The Kibana timeline is entirely blue - the connection stays open from query submission through two connection refreshes until results are delivered, with no sleep periods. The Elasticsearch timeline shows the query completing and results delivered immediately. The legend shows Lost time struck through, indicating it has been eliminated." /><p>With this combination of long polling and no more sleep periods, results are delivered as soon as they are ready.</p><h3>HTTP/1 degradation</h3><p>The theory is solid. So why does this Kibana deployment look so degraded when we turn on continuous polling?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltede864738a88e1cb/6a1710c947d49c178d2d8af2/517378a73d36bd95927b81b1f912ce465b7adf4c-800x412.gif" alt="Animated screen recording of a Kibana dashboard loading the Sample Logs Data dataset, showing multiple panels populating in sequence, including a response codes time series, a US map of total requests, unique visitors count, HTTP error rate metrics, and a Sankey chart of machine OS and destination data." /><p>The key is that this deployment is running over HTTP/1. In HTTP/1, HTTP requests are mapped 1:1 to TCP connections. So several long-lived polling requests are hogging the browser’s finite connection pool, causing other requests to be queued.</p><p>In HTTP/2+ on the other hand, network requests can share TCP connections via multiplexing, so we don’t run into this problem.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5cddb4d6767a1ccf/6a1710cb839dfa5056dcffcd/f60f3a37baf5ec16c9f1773f08855e7f9e3a7491-1536x1024.png" alt="Diagram comparing HTTP/1 and HTTP/2 for Kibana continuous polling. HTTP/1 requires one TCP connection per request, exhausting the browser's connection pool across six connections. HTTP/2 multiplexes multiple polling requests over a single TCP connection, avoiding pool exhaustion and maintaining performance." /><p>So, on HTTP/2+ continuous polling is a virtue but on HTTP/1 it becomes a vice.</p><p></p><p>HTTP/1</p><p>HTTP/2+</p><p>TCP connections</p><p>One per HTTP request</p><p>Multiplexed (many requests share connections)</p><p>Continuous polling behaviour</p><p>Degrades performance (connection pool exhaustion)</p><p>Full benefit (results delivered immediately)</p><h4>How Kibana detects HTTP protocol for optimal polling</h4><p>HTTP/2 is the recommended protocol and it’s the Kibana default since 9.0, so it would be a shame not to ship this performance enhancement. On the other hand, the HTTP/1 experience is so degraded that it isn’t acceptable to risk it on any on-prem deployments who haven’t yet upgraded their protocol. The answer is clear: we need to detect which protocol is in use and apply the optimal polling strategy.</p><p>It is certainly possible for the Kibana server to know which protocol it is speaking. But, there’s a catch: the limiting factor is the browser’s connection pool. That means that what really matters is what the <em>browser</em> is speaking.</p><p>Because of proxies, these are not always the same.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc61ff0abfe101eec/6a1710cd2867144b8893e412/13e38001fc4bd3fc60cfc69114fb9098fd745906-1970x786.png" alt="Architecture diagram showing three components in a horizontal chain: Kibana Server on the left, an optional Proxy in the centre, and Kibana Client on the right. The server-to-proxy hop is labelled with kibana.yml server.protocol, indicating the known protocol. The proxy-to-client hop is labelled with three question marks, indicating the protocol on that final hop is unknown and may differ." /><p>If we based our optimization on the server protocol, we could get things wrong in one of two ways.</p><ol><li><p>Apply continuous polling when we shouldn’t and degrade the experience.</p></li><li><p>Fail to apply continuous polling when we should and miss out on the optimization.</p></li></ol><p>Luckily, modern browsers provide a way to detect the protocol of the last network hop of any completed request through the use of a <code>PerformanceObserver</code>. So, we watch for the protocol of the first query submission and optimize based on that.</p>new PerformanceObserver((list) =&gt; {
  const entries = list.getEntries();
  const entry = entries.find(({ name }) =&gt; name.includes('/internal/search/'));
  if (entry) {
    this.protocolSupportsMultiplexing = ['h2', 'h3'].includes(entry.nextHopProtocol);
  }
});<h2>Lab results: continuous polling vs. traditional polling in Kibana</h2><p>To validate continuous polling, we created dashboards with query delays ranging from 1 to 23 seconds and measured load times with and without the optimization enabled. We then loaded the dashboards with and without continuous polling to measure the gains (we had a lot of fun with <a href="https://github.com/kertal/race-for-the-prize">race-for-the-prize</a>).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba4af840d8324923/6a1710ceb339d52fe076a0b6/5f19fb45c5307a7491037fe1ad1a302728793203-1200x742.png" alt="Bar chart showing lab test results for Kibana continuous polling: time saved versus traditional polling across query durations from 1 to 23 seconds. Savings vary between near-zero and 4.9 seconds depending on where queries complete relative to polling interval boundaries, confirming the sawtooth latency pattern predicted by the backoff schedule." /><p>The pattern echoes our original sawtooth diagram. For some query durations, the gains are small while for others they amount to several seconds.</p><h2>Conclusion</h2><p>This optimization successfully replaces the latency inherent in traditional polling with a more efficient continuous polling strategy. The primary challenge was implementing this optimization conditionally to prevent performance degradation on HTTP/1 deployments. We solved it using the browser’s <code>PerformanceObserver</code> to reliably detect the protocol in use for the final network hop.</p><p>Laboratory testing validates the theory, showing continuous polling delivers results as soon as they are ready. On average, this leads to a meaningful improvement in user experience, making data load up to 25% faster.</p><p>This work is the latest step in our commitment to driving down time-to-insight for our users. By making Kibana a more transparent proxy to Elasticsearch data, we push the limits of performance within our sphere of influence. More to come!</p><p>(In 2025, Thomas Neirynk gave an <a href="https://www.elastic.co/search-labs/blog/kibana-dashboard-rendering-time">excellent overview</a> of the methods and motivation behind improving Kibana dashboard performance. This is an update on that initiative.)</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/kibana-dashboard-performance-continuous-polling</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/kibana-dashboard-performance-continuous-polling</guid>
    <category><![CDATA[Kibana]]></category>
    <dc:creator><![CDATA[Drew Tate,Matthias Wilhelm]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4e81306b0c9f259/6a1710c147d49c34c42d8aec/d5cd43366f62de628c3a054ffb7bf0b05d7a1390-1500x600.png" length="0" type="image/png"/>
    <pubDate>Fri, 22 May 2026 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>