Iframes and Process Allocation
A common question I've encountered when consulting with teams that utilize
<iframe> in their web application
architecture is: Does an
<iframe> execute in parallel on a separate thread / in a dedicated process?
Web application process management is handled by the browser, and this can lead to interesting
and unexpected performance implications when using
In this tip, I detail a few different considerations regarding how Chromium browsers group frames together into shared processes and how an iframe based web architecture may have unique performance considerations when compared to ordinary web applications.
Many web applications are becoming Platforms that host other applications. Consider Microsoft Teams Apps, Stripe Apps, Slack Apps, Google Workspace Extensions, and so on. Platforms expose an Extension API and allow web developers to build custom extensions with access to certain privileged data, APIs, and authorization contexts.
Platform/Host applications do not directly execute these third-party extensions and instead expose the APIs to the Extension (for example, allowing a hosted extension to read User or Message data from Microsoft Teams, or Invoice Details from Stripe).
This is usually modeled as a hosted
<iframe> and a
postMessage based API contract.
The answer is that it will vary depending on how the
<iframe> element is configured within a Host!
Chromium uses a combination of tab-based isolation and site-based isolation. Generally, this means:
- Each new browser tab will be granted a dedicated Renderer process (and Main Thread) to run the web application in the address bar
- Iframes within a browser tab, if they differ in site origin (i.e.,
monday.comdiffer in site origin), will run in separate Renderer processes
- Iframes within a browser tab, if they share the same site origin (i.e.
dashboard.stripe.com/extensionshare the same origin of
stripe.com) and will run in the same Renderer process
Let's look a bit more closely at a few examples!
A Host Application runs directly in the user's browser tab. (i.e., the Microsoft Teams, Slack, Stripe Dashboard, etc.). When a user opens the Host Application, the browser will create a new Renderer process.
If the user opens another browser tab to a separate instance of the Host application, the browser will allocate another renderer process.
In this scenario:
- The two Renderer processes may not share code execution or DOM (i.e. a
<script>tag or Document Node in one tab does not become available to the other process)
Let's consider what happens when a user opens the third-party extension application iframe hosted on a different origin. This is the model that the Microsoft Teams / Microsoft 365 Apps framework has taken.
<!-- Within teams.microsoft.com host --> <iframe src="https://www.monday.com/teams_extension"></iframe>
Now, there's an iframe embedded in the page, pointing to a different origin, hosting the third-party application.
How does the browser allocate processes for this case?
When an iframe is opened within a site of a different origin, a new Renderer process must be created. This also creates a new Main Thread (and other threads) for that hosted extension to use for its isolated execution context.
This has interesting performance side-effects!
- The hosted extension does not share resources with the hosting process. This means it has its own threads to execute scripts, etc. and generally its execution should not impede the performance of the host application
- The hosted extension does not share memory with the hosting process (security feature). This also means that memory allocation within the hosted extension won't affect the host application. (Running out of memory in the hosted extension will not degrade the host)
- Processes must communicate with each other through
postMessage-- they cannot directly access each other's DOM
Note: You may see this case referred to as an OOPIF in Chromium source code. This stands for Out-of-Process Iframe.
Let's expand our example and observe some other unique considerations. Users often have multiple tabs open at once, even at times to the same application.
Consider the case where the user opens two tabs to Microsoft Teams, and in each tab, the user opens the Monday.com extension iframe. Chromium browsers will actually re-use the existing Monday.com Renderer process to host the two Monday.com iframes, while keeping the Microsoft Teams applications in separate processes!
In general, this means that the Monday.com extensions are now competing for resources on the same threads and memory! For example:
- A Long Task in one Iframe will affect the performance of the other
- Running out of memory in the one iframe will crash all iframes of the Monday.com extension hosted iframes
If your application is using a similar cross-origin iframe based approach, be aware that your hosted extension across the entire set of browser tabs will be competing for shared resources; you may want to throttle execution or release memory of inactive iframes.
It's important to note that although the Monday.com process is being re-used across each iframe, the browser is able to create separate
execution contexts for each instance of the
<iframe> within the same process. Execution contexts within a process will share resources
in the process (thread time and memory).
Let's consider a different hosted iframe architecture. In this architecture, hosted extensions are hosted on the same origin as the host. For example, these all share the same origin:
In fact, this is the model used by Stripe Apps! How does the browser manage processes in this case?
If both the host and the iframe within a host share the same origin, the browser will group their executions within the same process (even if the hosted iframe is sandboxed!).
This means that a host and a hosted extension within the same tab will:
- Compete for execution time on the same thread (i.e. a Long Task in one will degrade the other, as they interleave on the same thread)
- Share memory (i.e. running out of memory in the hosted extension will crash the host tab)
Although the browser will maintain separate execution contexts for the iframe and the host, the extension can directly degrade the performance of the host and vice-versa!
As mentioned previously, browsers will generate a new process for each browser tab, to host the site execution for that origin. In cases where there are multiple tabs, each hosting a same origin iframe, the iframes will not be shared (unlike same-origin cross origin iframes!).
This means that iframes executing within a host of the same origin compete with the host for thread time and memory resources, but not other iframes across the browser. Hosts do not share threads with each other because they are granted dedicated processes at the tab level.
A new browser API is available, called, Origin-Agent Clusters to signal to the browser that certain applications would perform better with dedicated resourcing rather than grouped.
Chromium exposes a tool for inspecting this process grouping! See this section for more details.
Browsers all differ in implementation, and other browsers will group processes across tabs and iframes differently! For example, Safari (as of writing) places iframes of separate origin in the same process as their host but doesn't share across tab!
Chromium also has exceptions to the general behavior explained above, such as in memory constrained environments (like low-end Android devices).
We explored how Chromium groups iframes and tabs into processes based on origin, and how this may affect the performance of a web architecture; with iframes being used more frequently to facilitate micro-frontend and third-party extension host architectures on the web, this is particularly important.
Understanding these process fundamentals and trade-offs can help web developers decide on an architecture that best fits their requirements and can help understand bugs and performance degradations in complex frontend systems.