Most WordPress page builders store your layout as a tree of shortcodes or blocks and turn it into HTML on every request. They also load their own CSS and JavaScript on every page, whether the page uses a slider or not. Kira Page Builder takes a different route: the page is rendered once, when you save, and the result is stored as plain HTML and CSS. This article explains how that works, why it matters for page speed, and where the trade-offs are.
What happens when you click Save
The editor runs in the browser. When you save, it does three things:
- It normalizes the layout (sections, columns, widgets and their settings) and stores it as JSON in the
_kpb_docpost meta. That is the source of truth the editor loads next time. - It renders that layout to static markup and stores it in
_kpb_html. - It generates the CSS for the elements on that page, scoped to the page, and stores it in
_kpb_css.
On the front end, PHP reads _kpb_html, prints the CSS, and echoes the markup. There is no layout engine running on the server per request. The work was done once, by the person who edited the page.
This is why the plugin requires the unfiltered_html capability to edit: the saved page is trusted HTML, written by an administrator or editor, and WordPress treats it as such.
Dynamic parts stay dynamic
Static does not mean frozen. Widgets whose output depends on the request (post title, post content, menus, the site logo, a posts grid, breadcrumbs) are saved as small <kpb-dyn> placeholders with their settings in a data attribute. On each request PHP fills those placeholders and leaves the rest of the markup untouched. A blog single template built with Kira is static markup with a few holes that PHP fills with the current post.
Share links work the same way: the saved HTML contains https%3A%2F%2Fweb9seo.com%2Fwhy-a-page-builder-should-save-static-html%2F and Why%20a%20page%20builder%20should%20save%20static%20HTML tokens, and PHP swaps them for the current page’s encoded URL and title. No script is needed to build a share link.
Zero front-end JavaScript by default
Kira’s widget contract is explicit: prefer CSS-only solutions (<details> for accordions, :target and :checked for toggles, scroll-snap for carousels). A widget may only ship JavaScript when it genuinely needs it, as a progressive enhancement that leaves the page working without it.
In practice, the plugin has one front-end bundle, build/front.js, and it is enqueued only when the rendered page contains a data-kpb- attribute. That attribute is set by the widgets that need it: entrance and scroll motion, counters, countdowns, carousels, before-and-after sliders, popups, the table of contents and the back-to-top button. A page made of headings, text, images, buttons and columns loads no JavaScript from Kira at all. The bundle itself is about 16 KB on disk.
What that means for Core Web Vitals
The three metrics Google reports are Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift. Static HTML with scoped CSS helps each of them in a direct way:
- LCP: the browser receives the final markup in the first response and can start painting immediately. There is no client-side render step and no builder stylesheet to download before the hero appears. Image widgets can be flagged to load immediately, so the main image is not lazy-loaded.
- INP: with no builder script running on the main thread, there is nothing to block input handling. The only script that can appear is the small bundle above, and only on pages that use those widgets.
- CLS: the CSS for every element is generated from the saved values, including per-device sizes, so the layout does not reflow when a late script runs.
None of this guarantees a green score on its own. A slow server, uncompressed images or a heavy theme will still hurt. But the builder stops being the reason.
The trade-offs, honestly
Saving rendered HTML has costs, and you should know them before you choose it.
- Pages must be rebuilt after some updates. When a plugin update changes section markup, stored pages still contain the old markup until you run Tools → Rebuild all pages. The plugin shows a notice when this is needed, but it is a step a request-time renderer never asks of you.
- Deactivating the plugin leaves unstyled content. The text, links and images are copied into the regular post content as a fallback, so nothing is lost, but the layout and styles stop applying until the plugin is active again.
- Per-request personalization is limited to dynamic widgets. If you need a page that changes for every visitor in ways the dynamic widgets do not cover, a static render is the wrong tool.
- Editing is restricted to trusted users. Because the saved HTML is not re-sanitized on output, only users with
unfiltered_htmlcan edit with Kira. On most sites that is the right policy anyway.
When it is the right choice
For marketing sites, service pages, documentation and blogs, the content changes when someone edits it, not when someone reads it. Rendering at save time matches how those pages actually behave, and it removes a layer of per-request work and front-end script that visitors were paying for on every load. If that describes your sites, a builder that saves static HTML is the simpler architecture, not just the faster one.