# Config and theme (/docs/concepts/config-and-theme)



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 [#the-config-entities]

| Entity         | What it holds                                                             |
| -------------- | ------------------------------------------------------------------------- |
| `screens`      | Every screen, keyed by `screenId`, each with its ordered block list       |
| blocks         | Per-instance `source`, `style`, and `options`, inside each screen entry   |
| theme          | Shared visual styling: per-block-type style entries and common style keys |
| `settings`     | Global defaults for `source` and `options`, keyed by block type           |
| `integrations` | Per-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 [#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 [#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.

```json
{
  "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 [#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.

<Callout type="warn" title="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.
</Callout>

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