JSON-first builder: getData() / load(), your backend owns the data
Most drag-and-drop builders hide your design inside a proprietary database you can't reach. BuilderJS does the opposite. It is a JSON-first builder: every design — email or web page — lives as a plain JSON tree that you read with getData() and restore with load(). That round-trip is lossless, so what you save is exactly what you reload, down to nested structure and element properties. Because the data is plain JSON and BuilderJS is a library you embed in your own DOM node (React, Vue, Svelte, Angular, Next.js, Laravel, or plain HTML), your backend owns persistence end to end. You decide the table, the file, the bucket, the schema. You can commit designs to git, diff them in code review, and migrate them with a script — no export wizard, no vendor account, no phone-home. This page explains the JSON-first model, how getData()/load() work for both email and page output, and why "your backend owns the data" is the whole point.
getData() and load(): one lossless JSON round-trip
BuilderJS keeps the design as a structured tree in memory while you edit. Call getData() and you get that tree as a serializable JSON object: the elements (it ships 42 element types), their property values (59 property controls), and their nesting — the full document, not a flattened snapshot. Hand that same JSON back to load() and BuilderJS rebuilds the exact editor state. Nothing is interpreted away or lossily compressed on the way out and back, which is what 'lossless round-trip' means in practice: save → reload → continue editing, with no drift. This matters because the JSON is your canonical artifact. The rendered HTML is a derivative you regenerate on demand; the JSON is the source you keep. You never have to scrape markup back into an editable form, because the editable form never left.
Your backend owns persistence — choose where the JSON lives
BuilderJS is the editor you embed, not a platform. It does not host pages, send email, or store your designs on someone else's server. getData() returns JSON to your code, and from there persistence is entirely yours: write it to MySQL or Postgres as a JSON/text column, drop it in SQLite, save a file, or push it to S3. The reference PHP backends in the package (MySQL/SQLite/S3 save, upload, auth, realtime) are working examples you copy and own — you can keep them or port the same contract to Node, Go, or Python. Either way the data model is in your control, so there is no usage metering, no per-seat counter, and no proprietary store to be evicted from. Pair that with the one-time CodeCanyon license (item 27146783, Regular $52 / Extended $99, self-hosted source you own) and there is nothing to lock the JSON away.
Version designs in git, diff them in review
Because a design is just JSON, you can treat it like any other source artifact. Commit it alongside your application code, branch it, and open a pull request when a template changes. A reviewer sees a structured diff — which element was added, which property value moved — instead of squinting at a screenshot or a blob of minified HTML. You can write migration scripts that walk the tree and rewrite a property across hundreds of saved designs, run them in CI, and roll back with git if something looks wrong. Stable, inspectable JSON is what makes all of that possible; an opaque builder database is not something you can meaningfully diff or revert. This is the practical shape of 'no vendor lock-in': your designs are text, your history is git, and your tooling is whatever you already use on code.
Same JSON, two outputs: page HTML and Outlook-safe email
The JSON tree is output-agnostic. From one stored design BuilderJS can render modern page HTML (current CSS, the markup you embed in YOUR app or hand to YOUR hosting), or run it through the EmailExportPipeline to produce Outlook-safe email HTML: flexbox converted to tables, SVG rasterized to PNG, @media mobile-stacking, MSO conditional comments, and inlined CSS. The package includes 30+ templates and 200+ samples that were Litmus-tested across 22 email clients, so the email path is built for real inboxes. To be exact about the division of labor: BuilderJS builds the template and the markup — you bring the sending for email and the hosting/publishing for pages. The value of JSON-first here is that you keep one editable source and decide at render time whether this design becomes a page or an email.
No lock-in, by construction
Vendor lock-in usually shows up the day you want your work out. Plenty of hosted builders keep your designs in a database you can't reach and gate clean code export behind a paid tier, so leaving means rebuilding. BuilderJS sidesteps that whole category: the design is already JSON in your database, the HTML is already a function you call, and the editor source is already on your servers under a one-time license. There is no SaaS tier between you and your data and no monthly fee to keep access to it. If you want to see the round-trip before you commit, the live demo runs at builder.emotsy.com. When you're ready, read /one-time-license/ for the ownership model and /embed/ for mounting the editor in your stack.
Frequently asked questions
-
What exactly does getData() return?
A serializable JSON object representing the full design tree — every element (42 types), its property values (59 controls), and the nesting between them. It is the complete editable document, not a rendered HTML snapshot. You pass the same object to load() to rebuild the exact editor state.
-
Is the getData()/load() round-trip really lossless?
Yes. What load() restores is what getData() produced, including nested structure and element properties — you can save, reload, and keep editing with no drift. The JSON is the canonical source; the rendered HTML (page or email) is a derivative you regenerate from it on demand.
-
Where is my design data stored?
Wherever you put it. BuilderJS is the editor you embed, not a platform — it doesn't store designs for you. getData() hands JSON to your code, and your backend persists it (MySQL, Postgres, SQLite, a file, S3, etc.). The package's reference PHP backends are working examples you copy, own, and can port to Node, Go, or Python.
-
Can I version and diff designs in git?
Yes — that's a core benefit of JSON-first. Commit the JSON like any source file, branch it, and review structured diffs in a pull request instead of comparing screenshots. You can also script migrations that rewrite properties across many saved designs and roll back with git.
-
Does the same JSON work for both email and web pages?
Yes. The JSON tree is output-agnostic. BuilderJS can render modern page HTML, or run the design through the EmailExportPipeline to produce Outlook-safe email HTML (tables, inlined CSS, MSO conditionals, mobile-stacking). BuilderJS builds the markup; you bring the sending for email and the hosting/publishing for pages.