> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bytesell.io/llms.txt
> Use this file to discover all available pages before exploring further.

# theme.json

> Manifest fields.

`theme.json` is required, at the theme root. A directory containing one is a
theme root, for both publishing and git deploy detection.

```json theme.json theme={null}
{
  "name": "Minimal",
  "description": "A clean storefront for digital goods.",
  "long_description": "Longer copy for the marketplace listing page.",
  "author": "ByteSell",
  "author_url": "https://bytesell.io",
  "category": "storefront",
  "tags": ["storefront", "minimal", "dark"],
  "preview_images": ["assets/preview-1.png", "assets/preview-2.png"],
  "thumbnail": "assets/thumb.png",
  "demo_url": "https://demo.example.com",
  "price_cents": 0,
  "currency": "USD",
  "schema": 2,
  "builder": "full"
}
```

Unknown keys are ignored. A malformed manifest does not fail a publish except
where noted below.

## Listing fields

These become the theme's marketplace listing.

| Field              | Type      | Notes                                                                         |
| ------------------ | --------- | ----------------------------------------------------------------------------- |
| `name`             | string    | Trimmed. Overrides the name supplied at publish. Falls back to the slug.      |
| `description`      | string    | Trimmed, empty becomes absent.                                                |
| `long_description` | string    | Listing page copy.                                                            |
| `author`           | string    | Stored as the author name.                                                    |
| `author_url`       | string    |                                                                               |
| `category`         | string    |                                                                               |
| `tags`             | string\[] | Non-strings dropped, each trimmed, empties dropped. A non-array becomes `[]`. |
| `preview_images`   | string\[] | Theme-relative paths, resolved to immutable asset URLs.                       |
| `thumbnail`        | string    | Same resolution. Falls back to `preview_images[0]`.                           |
| `demo_url`         | string    |                                                                               |
| `price_cents`      | integer   | Negative or non-integer becomes `0`.                                          |
| `currency`         | string    |                                                                               |

`is_free` is derived from `price_cents == 0` and is not a field you set.

<Warning>
  A path in `preview_images` that is not a real file in the bundle is dropped
  silently, never rendered as a broken image. If your previews do not appear,
  check the paths against what you actually shipped.
</Warning>

## `schema`

The schema generation your theme is written against. An integer, at least 1.
Absent, wrong type, negative or fractional all resolve to `1` rather than
failing.

| Version | Adds                                                                |
| ------- | ------------------------------------------------------------------- |
| `1`     | Sections, inline `blocks { }`, the nine setting kinds               |
| `2`     | Theme-level blocks in `blocks/<name>.slurp`, and `@theme` targeting |

The gate is one-directional. A deployment newer than the theme is accepted. A
theme declaring a version higher than the deployment supports is rejected:

```
theme.json declares schema 3, but this ByteSell deployment supports up to 2.
Publishing would silently drop settings this theme declares.
Update ByteSell, or build the theme against schema 2.
```

## `builder`

Which editing surface merchants get. `"full"` or `"simple"`.

<CardGroup cols={2}>
  <Card title="full" icon="sliders">
    Section tree, click-to-select on the canvas, SEO panel, nested block
    editing. The default.
  </Card>

  <Card title="simple" icon="list">
    One scrolling column of forms beside the preview. No section tree, no
    click-to-select, no SEO panel.
  </Card>
</CardGroup>

The value is trimmed and lowercased, and anything other than `simple` resolves
to `full`. A typo cannot make a theme unpublishable.

`builder` is presentation only. Both shells call the same endpoints with the
same scopes, and the server does not read this value. It grants and restricts
nothing.

Use `simple` for a theme small enough that a section tree adds overhead, such as
a link-in-bio layout. See [The builder](/themes/builder).

## `version`

The publish path does not read `version`. The published version comes from the
publish request, or the server bumps the patch of the highest existing clean
semver.

<Warning>
  Changing `version` in `theme.json` does not produce a new version. It is read
  only by the dashboard when detecting a theme in a connected repository, for
  display.
</Warning>

## Related files

| File                          | Required | Malformed                                                                        |
| ----------------------------- | -------- | -------------------------------------------------------------------------------- |
| `config/settings_schema.json` | no       | Must be valid JSON. Shape is not validated, and a non-array is ignored at merge. |
| `config/migrations.json`      | no       | Valid JSON **and** a valid migration map, or the publish fails.                  |

`config/migrations.json` renames things across a schema change so merchant
content survives:

```json config/migrations.json theme={null}
{
  "section_renames": { "Banner": "Hero" },
  "setting_renames": { "Hero": { "title": "heading" } },
  "block_renames":   { "link_item": "link" }
}
```

`setting_renames` is keyed by the **post-rename** section type.
