AppbrewDevelopers
Concepts

Config and theme

How app config, themes, and settings resolve.

The app config is one JSON document with a handful of top-level entities. Everything a screen renders resolves from these, in a defined order.

The config entities

EntityWhat it holds
screensEvery screen, keyed by screenId, each with its ordered block list
blocksPer-instance source, style, and options, inside each screen entry
themeShared visual styling: per-block-type style entries and common style keys
settingsGlobal defaults for source and options, keyed by block type
integrationsPer-integration configuration: API keys, flags, endpoints

Blocks are not stored separately; they live inside their screen's layout. The theme and settings exist so you don't repeat the same styling and defaults on every instance.

Style resolution

When a block asks for its style (via useBlockStyle), three layers deep-merge, later layers winning:

  1. Theme style — a shared theme entry the block opts into (for example, a common product-collection key several block types reuse).
  2. Theme block style — the theme's entry for this block type: the key componentId--variant if the block has a variant and the theme defines it, otherwise componentId.
  3. Block style — the instance's own style object from its config entry.

So the theme sets the look once per block type, a variant refines it, and an individual instance overrides only what it needs. An instance with an empty style simply inherits the theme result.

Settings resolution

source and options resolve the same way (via useBlockSettings), with global settings playing the role the theme plays for styles:

  1. Global settings — the settings entry under componentId--variant, falling back to componentId. These are defaults for every instance of the type.
  2. Block settings — the instance's own source and options, which override the globals.

A block can also extend another type's settings entry (for example, a recommendations block inheriting product-collection defaults); those sit below the globals in the merge. As a rule of thumb, the closer a value sits to the instance, the higher its precedence.

{
  "settings": {
    "product-card": { "options": { "showVendor": false } }
  }
}

With this global entry, every product-card hides the vendor, except an instance whose own options set "showVendor": true.

Drafts and the live theme

An app has one live theme (the config installed apps actually fetch) and any number of draft themes. Edits always target a draft: you can restructure screens, move blocks, and change styles without affecting users. When the draft is ready, an operator publishes it, and it becomes the live config for every installed app on the next fetch.

Never edit the live theme directly

Config mistakes on the live theme reach real users immediately. Make changes on a draft, verify them, and let publishing be the deliberate step that ships them.

Config changes need no app-store release because publishing a theme is a backend event that apps pick up on launch. See Architecture for the two release tracks, and State and data for the hooks that read these resolved values.

On this page