BuilderJS

Running BuilderJS self-hosted, on-prem, and air-gapped

If your deployment sits behind a firewall, inside a private VPC, on a customer's on-prem hardware, or on a network with no outbound internet at all, most embeddable builders are a non-starter: they phone home to a vendor cloud SDK for licensing, asset hosting, or telemetry. BuilderJS is built the opposite way. It is a vanilla-JavaScript, framework-agnostic drag-and-drop editor for HTML email and web pages that you buy once (CodeCanyon, Regular $52 / Extended $99), self-host as source, and run with no runtime dependency on any vendor service. There is no account check, no usage meter, and no callback to a license server. This guide explains exactly how to run it fully offline — including the one knob that matters, loadAssets:false, which opts out of the two CDN peer-dependencies the engine would otherwise auto-inject so you can serve them from your own origin instead.

Mount it

// Air-gapped mount: opt out of the CDN peer-deps and self-host them.
  // builder.js + builder.css are served from YOUR origin (no npm import);
  // loading builder.js attaches the global window.Builder.
  //
  // In your HTML <head>, self-host the two peer-deps instead of the CDN:
  //   <link rel="stylesheet" href="/vendor/material-symbols-rounded.css">
  //     (href must keep the "Material+Symbols+Rounded" family token)
  //   <script src="/vendor/bootstrap.bundle.min.js"></script>
  //     (must define window.bootstrap with Bootstrap's Modal)
  //   <link rel="stylesheet" href="/builderjs/builder.css">
  //   <script src="/builderjs/builder.js"></script>
  
  const builder = new window.Builder({
    mainContainer: '#bjs-canvas',        // REQUIRED — CSS selector string
    widgetsContainer: '#bjs-widgets',    // optional — CSS selector string
    settingsContainer: '#bjs-settings',  // optional — CSS selector string
    loadAssets: false,                   // skip CDN auto-injection (air-gap)
  });
  
  // load(themeJson, themeTemplatesJson, themeConfigData, mediaUrl) — 4 args.
  // mediaUrl points at YOUR internal asset host, not a public CDN.
  builder.load(themeJson, themeTemplatesJson, themeConfigData, '/internal-media/');
  
  // Persist offline: POST getData() JSON to your own backend route.
  const json = builder.getData();
  // There is NO destroy(); React discards the DOM on unmount.

What "air-gapped" actually requires from a builder

An air-gapped or strict on-prem environment has no outbound internet, so anything the editor fetches at runtime from a third-party origin will simply fail. The audit you have to pass is: does the editor make any network call you don't control? BuilderJS itself ships as two static files you serve from your own origin — builder.js and builder.css — and stores nothing remotely; getData() hands the design JSON back to your code and your backend owns persistence. There is no licensing handshake, no telemetry beacon, and no hosted asset store. The single thing to be aware of is that the engine has two runtime peer-dependencies it normally pulls from a CDN. That auto-injection is the only outbound touch, and it is exactly what loadAssets:false turns off.

loadAssets:false — opt out of the CDN peer-deps

By default the constructor runs in 'auto' mode: at construction time it checks whether the host page already loaded its two peer-deps and, if missing, injects them. Those peers are Material Symbols Rounded (the icon font used across the chrome, referenced from Google Fonts) and Bootstrap's JS bundle (used for the Change-Theme, Asset-Upload, and Alert modals, fetched from jsDelivr). On a connected page that is a convenience. In an air-gapped deployment it is a broken request. Pass loadAssets:false and the engine skips both injections entirely — this behavior is explicit in the source, commented for 'Air-gap / China deployments.' You then self-host those two assets and add your own <link>/<script> tags pointing at your origin. Nothing else in the editor reaches the network.

Self-host the two peer assets

With loadAssets:false set, you become responsible for the icon font and Bootstrap JS. Download both once on a connected machine, vendor them into your project, and serve them from the same origin as builder.js / builder.css. The detection BuilderJS uses is deliberately loose, so self-hosted variants are recognized fine: it looks for any stylesheet whose href contains 'Material+Symbols+Rounded', and for window.bootstrap.Modal being a function. As long as your self-hosted font stylesheet keeps that family token in its URL and your Bootstrap bundle defines window.bootstrap, the chrome renders correctly and the Change-Theme / upload / alert modals work — with no request ever leaving your network.

What you own, and what stays your job

Because BuilderJS is the editor you embed — not a platform — self-hosting is the default, not an enterprise upsell. You own the full source under a one-time license, run it on your own server, and the design data is plain JSON in your own database, file, or object store. The boundary is the same as anywhere else: BuilderJS builds the markup (page HTML, or Outlook-safe email HTML via its export pipeline) and round-trips designs as JSON through getData() / load(); it does not send email, host pages, or publish anything. In an air-gapped setup that division is a feature — the editor produces artifacts your own internal sending or hosting layer consumes, and no part of the workflow assumes outbound connectivity.

Frequently asked questions

Explore