Trees in the cloud

Your Bubble app is JSON, not code.

When you deploy your Bubble app, you might assume Bubble compiles your app into JavaScript and sends it live.

In fact, Bubble generates no source code for your app. Your app, in its entirety, is a JSON tree of data. The editor is simply a wrapper on top of this tree that lets you view and edit it. Run mode executes it. There is nothing else.

The editor is a JSON wrapper

Each ‘node’ of your app - a page, element, action, expression, option set - is a node in the JSON tree. The tree looks something like this:

PagePropertiesWorkflowsElementsname: My Pagewidth: 800bgcolor: paperWorkflow 1GroupTriggerActionsTextButtontype: Page is loadedorder: 0Action 1Action 2text: Submitstyle: primaryon_click: Workflow 1type: Navigateto: /dashboard
A page, idealised. Pages branch into properties, workflows, and elements. Workflows split into a trigger and an ordered list of actions. Elements can themselves contain elements.

So when you edit an element, you're updating the JSON node for that element. When you add an action, you're inserting a new action node into the JSON for that workflow.

Lazy JSON

Because it's JSON, Bubble can fetch only what it needs. If you're on /dashboard, you don't need the JSON for /login. But you do need to know /login exists - actions might navigate to it, so its presence has to be visible to the rest of the app.

Bubble does its best to load only the JSON it needs to do a given job, but it's still much more than the strict minimum. Option sets, for example, are loaded on every page even when most are unused.

This is also why the editor can be slow. A large Bubble app can be 100MB+ of JSON. The editor needs to know even moreabout your app than run mode, so it has to fetch and work with a lot of the tree at once. It's difficult to operate on a slice when navigating the whole tree is the point.

Looking at a node

At the byte level, a single element node looks something like this:

{
  "abCD1": {
    "properties": {
      "type": "Group",
      "width": 320,
      "height": 200,
      "container_layout": "row",
      "bgcolor": "var(--color_primary)"
    },
    "elements": {
      "xyZ23": {
        "properties": {
          "type": "Text",
          "text": "Hello world",
          "style": "style_body_default"
        }
      }
    }
  }
}
Illustrative. Bubble's real keys vary, but the shape is consistent: opaque ids, a properties bag, nested elements, and references by id to other parts of the tree.

Two things to notice. First, the ids (abCD1, style_body_default) are how nodes refer to each other - an action references an element by id, a style lives as its own node elsewhere, an option-set value is a reference rather than a copy. Second, the tree nests: a Group is an element that contains elements, and those elements can themselves be Groups containing more.

For Bubble's own account of why they chose this design, see Trees in the Clouds on the Bubble engineering blog - the post this lesson is named for.