Skip to content

Settings Schema Walkthrough

TL;DR: Theme-level settings vs. section/block settings, and when to use which.

Shopify has three separate places where settings can live. Mixing them up is a common mistake even for experienced theme developers moving between projects, so here’s how we draw the line on Solis.

Solis’s own config/settings_schema.json already has real content in it, theme_info and several settings groups. Open it and read through what’s there before adding anything new, the examples below are illustrative, not a from-scratch starting point.

LevelFileScopeExample
Themeconfig/settings_schema.jsonEvery page, set once in “Theme settings”Brand color palette, base font
SectionInside the section’s own {% schema %}That section instance onlyA banner’s heading text
BlockInside the block’s own {% schema %}That block instance onlyOne quote’s author name
AskIf yes →
Should every page share this value with no per-instance variation?Theme setting
Does this vary per section instance, but every block within it shares the same value?Section setting
Does this vary per individual block instance?Block setting
// ❌ WRONG — a brand color defined per-section means every banner,
// every testimonial, every footer independently "chooses" a brand color,
// creating inconsistency and a maintenance nightmare across dozens of sections
// sections/image-banner.liquid schema (excerpt)
{ "type": "color", "id": "brand_color", "label": "Brand color", "default": "#1a1a1a" }
// ✅ RIGHT — one theme-wide setting, referenced everywhere via {{ settings.color_primary }}
// config/settings_schema.json (excerpt)
{ "type": "color", "id": "color_primary", "label": "t:labels.color_primary", "default": "#1a1a1a" }
// config/settings_schema.json (excerpt)
[
{
"name": "theme_info",
"theme_name": "Solis",
"theme_author": "Your Company",
"theme_version": "1.0.0",
"theme_documentation_url": "https://example.com/docs",
"theme_support_url": "https://example.com/support"
},
{
"name": "t:general.colors",
"settings": [
{ "type": "header", "content": "t:labels.colors_heading" },
{ "type": "color", "id": "color_primary", "label": "t:labels.color_primary", "default": "#1a1a1a" }
]
}
]

You can access this setting anywhere in Liquid through the settings object, like this: {{ settings.color_primary }}. The theme_info block is required by Theme Store review (see Schema.json Best Practices).

Notice the strings that start with t:. These pull text from locales/en.default.schema.json instead of hardcoding English words directly, so the theme editor’s interface can be translated into other languages. Use this t: pattern for every label and content string in your schema, not just some of them.

// ❌ WRONG — hardcoded English, can't be localized for the theme editor UI
{ "type": "header", "content": "Colors" }
// ✅ RIGHT — pulls from locales/en.default.schema.json
{ "type": "header", "content": "t:labels.colors_heading" }
// locales/en.default.schema.json (excerpt)
{
"general": {
"colors": "Colors"
},
"labels": {
"colors_heading": "Color palette",
"color_primary": "Primary color"
}
}

Single-property vs. multi-property settings

Section titled “Single-property vs. multi-property settings”

Skeleton Theme’s own rules (worth following) draw a clear line between two situations.

{% comment %} A setting that maps to ONE CSS property → use a CSS variable {% endcomment %}
<div class="collection" style="--gap: {{ block.settings.gap }}px">
{% content_for 'blocks' %}
</div>
{% stylesheet %}
.collection { gap: var(--gap); }
{% endstylesheet %}
{% schema %}
{ "settings": [{ "type": "range", "id": "gap", "label": "Gap", "min": 0, "max": 100, "unit": "px", "default": 16 }] }
{% endschema %}
{% comment %} A setting that changes MULTIPLE properties at once → use a CSS class, not several variables {% endcomment %}
<div class="collection {{ block.settings.layout }}">
{% content_for 'blocks' %}
</div>
{% stylesheet %}
.collection--full-width { /* several properties */ }
.collection--narrow { /* several different properties */ }
{% endstylesheet %}
{% schema %}
{ "settings": [{ "type": "select", "id": "layout", "label": "Layout", "values": [
{ "value": "collection--full-width", "label": "Full width" },
{ "value": "collection--narrow", "label": "Narrow" }
] }] }
{% endschema %}

Why mixing these two up is a common mistake

Section titled “Why mixing these two up is a common mistake”
/* ❌ WRONG — using several individual CSS variables for what is really
one cohesive "layout mode" choice. Easy for the variables to drift
out of sync with each other as the theme evolves. */
.collection {
display: var(--collection-display);
gap: var(--collection-gap);
grid-template-columns: var(--collection-columns);
}
/* ✅ RIGHT — one class encapsulates the whole layout mode as a single,
internally consistent unit */
.collection--full-width {
display: grid;
gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

If you find yourself adding a third or fourth CSS variable to control what’s really one visual “mode,” that’s usually a sign. It means you should combine them into a single select setting mapped to a CSS class instead.

✅ Do❌ Don’t
Before you add a new setting, ask yourself: “Does this vary per instance, or is it shared everywhere?” This one quick check prevents most setting-placement mistakes.Defining the same setting (like a brand color) separately in multiple sections instead of once at the theme level. This creates inconsistency and makes it painful to rebrand the whole store later.
Add the t: prefix to every schema string as you write it, not as a cleanup job later.Hardcoding schema label/content strings “temporarily” and never coming back to add the t: prefix.
When a section or block builds up more than 3 to 4 related CSS custom properties that all control one visual mode, consider combining them into a select setting with CSS classes instead.Overusing CSS custom properties for something that should be a class-based variant setting. This leads to a tangle of variables that can end up set in combinations that don’t make sense together.
  • Theme-wide settings go in config/settings_schema.json. Per-instance settings go in the section or block’s own schema.
  • Always add t: to schema strings. Never hardcode English text.
  • One CSS property changing means use a CSS variable. Several properties changing together means use a CSS class via a select setting.