Architecture
From remote config to rendered screens: the Appbrew runtime.
An Appbrew app has two halves. The half you ship to the app stores is a React Native shell: navigation setup, the block registry, integration initialization, and the native modules the app needs. The half that decides what users actually see is a JSON config that lives on Appbrew's backend and is fetched when the app launches.
The launch sequence
On launch, the shell fetches the app's config from Appbrew's backend and caches it locally so the app still opens offline. The config describes everything structural:
- Screens — which screens exist and which blocks each one contains, in order
- Blocks — for each block, its type, its data, its styling, and its behavior flags
- Theme — shared visual styling that blocks inherit
- Settings — global defaults that apply across block instances
- Integrations — per-integration configuration such as API keys and feature flags
The shell then sets up navigation from the config, initializes any configured integrations, and renders the first screen.
The rendering pipeline
Each screen renders its blocks in the order the config lists them. A block entry names a componentId; the shell looks that id up in the block registry (a map of componentId to React component) and renders the matching component. The component reads its own data and styling through hooks, which in turn pull from the app store, Shopify's APIs, and Appbrew services.
flowchart TD
A[App config JSON] --> B[Screens]
B --> C[Blocks, in order]
C --> D[Hooks from @gauntlet/state]
D --> E[Shopify APIs]
D --> F[Appbrew services]When a user adds to cart, searches, or opens checkout, the same hooks write back to the store, analytics events fire to every registered tracker, and the UI updates reactively.
What you write vs what config decides
The split has one practical consequence to hold onto before you write any code:
UI structure is config. Code defines block types.
You never hardcode "the home screen shows a hero banner above a product rail." Instead, you write (or reuse) a banner block type and a product rail block type, and the config places instances of them on the home screen in that order. Moving a block, restyling it, or removing it entirely is a config change; it ships without touching code or the app stores.
Conversely, anything the config cannot express yet is a code change: a new block type, a new integration, a new native capability. That code registers itself with the shell (see Screens and blocks) and then waits for the config to place it.
Two release tracks
Config changes go live when a theme is published: instantly, to every installed app. Code changes ship through an app-store release. Knowing which track a change rides on tells you how fast it can reach users.
Where to go next
- Screens and blocks — the block contract in detail
- Config and theme — how styles and settings resolve
- State and data — the hooks blocks read data through

