Package layout
A theme is a set of files. Paths are normalized on the way in and anything that is not a legal theme path is refused before any of it is read, so nothing later has to wonder about ../, absolute paths or files outside the theme's own folders.
Path rules
Every path in a package must be:
- forward slashes only, no leading slash, at most 200 characters;
- no
.or..segment, no empty segment, no drive letter or:, no control characters, no leading or trailing space in a segment; - at most four levels deep;
- inside one of the ten folders below (or the manifest alone at the root);
- made of ASCII letters, digits,
-,_,.and@; - ending in an extension the platform serves:
.liquid,.json,.css,.js,.mjs,.svg,.md,.txt,.png,.jpg,.jpeg,.webp,.avif,.gif,.ico,.woff2,.woff,.mp4,.webm.
Files an operating system leaves behind — .DS_Store, Thumbs.db, desktop.ini, anything starting with ._ — are dropped rather than refused. Two files at the same path (compared exactly, so Hero.liquid and hero.liquid are two paths) are an error.
Size caps
| Cap | Value |
|---|---|
| Files in a package | 1,500 |
| Package | 60 MB |
| One file | 10 MB |
| One text file | 512 KB |
| Liquid steps per page render | 1,000,000 |
| Liquid recursion per render | 24 |
The ten folders
| Folder | Holds | Rule |
|---|---|---|
layouts/ |
theme.liquid and any other layout, as .liquid |
theme.liquid is required; a template names another layout with "layout" |
templates/ |
{type}.json or {type}.{suffix}.json |
one of the template types below; home, page and 404 are required, contact and gallery recommended |
sections/ |
{name}.liquid with a {% schema %}, and the five group files {group}-group.json |
names are letters, digits, hyphens and underscores, at most 64 characters |
blocks/ |
{name}.liquid theme blocks with a {% schema %} |
same naming rule |
snippets/ |
{name}.liquid, rendered with {% render 'name' %} |
a render naming a snippet the theme lacks is an error |
config/ |
settings_schema.json, settings_data.json, presets.json, product_fields.json |
settings_schema.json is required; any other file here is a warning (config.unknown) |
assets/ |
CSS, JavaScript, pictures, fonts, video | addressed with asset_url, served content-hashed and cacheable for a year |
locales/ |
en.default.json, fr.json, fr-CA.json … |
named ^[a-z]{2}(-[A-Z]{2})?$ with .default marking the fallback language |
screenshots/ |
listing pictures | a theme without any is warned |
documentation/ |
README.md, IMAGES.md, SAMPLES.json … |
a theme without any is warned |
A file of the wrong kind in layouts, sections, blocks, snippets, templates or locales (a .txt under sections/) is an error (package.misplaced).
abizvo-theme.json
The manifest says who made the theme, what it is and what it asks of the platform. It is read with snake_case property names, comments and trailing commas tolerated.
{
"schemaVersion": 1,
"themeApi": "1.0",
"key": "starter",
"name": "Abizvo Starter",
"version": "1.6.0",
"developer": "Abizvo",
"category": "Starter",
"description": "The official reference theme.",
"documentationUrl": "https://example.com/docs",
"supportUrl": "https://example.com/support",
"industries": ["Business", "Professional Services"],
"features": { "animations": true, "javascript": false, "galleries": true, "video": true, "forms": true, "dynamicSources": true },
"pages": [
{ "name": "Home", "slug": "home", "template": "home", "home": true },
{ "name": "About", "slug": "about", "template": "page.about" },
{ "name": "Contact", "slug": "contact", "template": "contact", "showInNavigation": true }
]
}
| Field | Rule |
|---|---|
schemaVersion |
must be 1 |
themeApi |
must be one the platform supports: 1.0 |
key |
the theme's handle: 2–40 lowercase letters, digits and hyphens, starting with a letter (^[a-z][a-z0-9-]{1,39}$). A key belongs to the product that first published it |
name |
required, at most 40 characters |
version |
a semantic version major.minor.patch, no pre-release; each part is a number (major and minor up to 999, patch up to 9999). A release requires the manifest's version to equal the draft's |
developer |
required |
category |
one of Photography, Portfolio, Business, Agency, Real Estate, Restaurant, Fashion, Jewelry, Beauty, Professional Services, Retail, Technology, Starter |
description, documentationUrl, supportUrl, industries |
free text and a list of words for the listing |
features |
animations (loads the motion runtime on every page even where no setting asks for it), javascript (a theme with script that does not declare it is warned), galleries, video, forms, dynamicSources |
pages |
the pages a new site starts with: each needs a name, a valid slug, and a template the theme has; exactly one carries "home": true. A theme that lists none is warned, and a new site then starts with a home page only |
config/settings_schema.json
An array of named groups, each becoming one panel of Theme settings in the editor:
[
{ "name": "Colors", "settings": [ { "type": "color_scheme_group", "id": "color_schemes", "label": "Colour schemes", "definition": [ … ], "role": { "background": "background", "text": "text" } } ] },
{ "name": "Typography", "settings": [ { "type": "font_picker", "id": "heading_font", "label": "Headings", "default": "fraunces" } ] }
]
Every setting id is unique across the whole file; two settings sharing one is an error. A theme has exactly one color_scheme_group, and it lives here — a scheme group inside a section's schema is an error. What each setting may declare is on Settings.
config/settings_data.json
The values the theme starts with, under current:
{ "current": { "heading_font": "fraunces", "page_width": 1280, "color_schemes": { "scheme-1": { "name": "Paper", "settings": { "background": "#fbfaf7", "text": "#1d1b17" } } } } }
Every value is normalized against the schema by the theme check (an invalid one is an error; a value for a setting the theme no longer has is noted and left out).
config/presets.json
The theme's named looks — an array of { "name", "description", "screenshot", "settings" }. Each look is a set of global setting values (colour schemes included) that the editor's Looks row applies in one step. A look without a name is an error; each value is checked like settings_data.json.
config/product_fields.json
The product custom fields the theme reads (COM-018) — an array of { "key", "label", "type", "options", "info", "category", "filterable" }. key is lowercase letters, digits and underscores, starting with a letter (what the theme reads as product.fields.{key}); type is one of text, textarea, richtext, number, measurement, select (with options), checkbox, date, url, color, image, product, product_list and list; filterable offers a select or checkbox field as a collection filter. Nothing is created from it on its own: once the theme is a site's live theme, Inventory → Product fields (and every product's page) offers the owner the fields the workspace does not keep yet, in one click. A malformed entry, an unknown type or a key offered twice is an error; at most 50.
[
{ "key": "condition", "label": "Condition", "type": "select", "options": ["Pristine", "Excellent", "Good"], "filterable": true },
{ "key": "provenance", "label": "Provenance", "type": "list" },
{ "key": "complementary", "label": "Pairs with", "type": "product_list" }
]
templates/{type}[.{suffix}].json
A template is a JSON document of sections in order. The suffix makes an alternate template (page.about, entry.news); it is 1–48 lowercase letters, digits, hyphens and underscores.
Template types: home, page, contact, service, portfolio, gallery, album, blog, article, entry, 404, search, custom, product, cart, collection, list-collections, password, customers. entry is a collection entry's own page (entry.json for every collection, entry.{handle}.json for one). product is a product's own page (/products/{handle}), drawn with the product global; a theme without product.json still has product pages — the platform draws them inside the theme's chrome. What each renders is on Templates and pages. cart is the cart page (/cart) on a site that sells, drawn from the cart global; paying stays the platform's checkout step. collection is a product collection's page (/collections/{handle}, /collections/all) drawn with the collection global, and list-collections the list of them (/collections) drawn from product_collections; a theme without them has no collection pages. blog and article are a blog's list and its posts (/{blog}, /{blog}/{post}). password is the storefront password page (usually with its own layouts/password.liquid). customers holds the account pages a theme may draw — ship them in Shopify's folder, templates/customers/login.json, account.json, order.json and addresses.json, which load as customers.login and so on.
{
"schema_version": 1,
"name": "About",
"layout": "theme",
"sections": {
"hero": {
"type": "hero",
"settings": { "min_height": 86 },
"responsive": { "mobile": { "min_height": 70 } },
"blocks": {
"title": { "type": "heading", "settings": { "text": "Tell your story", "tag": "h1" } },
"actions": { "type": "buttons", "blocks": { "primary": { "type": "button", "settings": { "label": "Book a call", "link": "action:booking" } } }, "block_order": ["primary"] }
},
"block_order": ["title", "actions"]
},
"story": { "type": "rich-text", "disabled": false, "settings": {} }
},
"order": ["hero", "story"]
}
sectionsis keyed by id (letters, digits, hyphens, underscores, at most 64 characters);orderlists the ids that render, in order. An id inorderthe template lacks is a warning.- A section's
typenames a file insections/; an unknown type is an error, and a section placed where its schema'senabled_on/disabled_onforbids is an error. disabled: truekeeps a section in the template and leaves it off the page.responsiveholdstabletandmobileoverrides of settings marked"responsive": true; any other screen name is noted and ignored.blocksandblock_ordernest to a depth of 6; a block'sstatic: truemarks one the section's markup places itself with{% content_for 'block' %}(it can be edited and hidden, not removed or moved).- A section's
reusablenames a saved section of the site; the placement then renders the saved content and its own settings are ignored. layoutnameslayouts/{layout}.liquid(themeby default); a layout the theme lacks is an error.schema_versionis1; a higher one is an error ("written by a newer version of the platform").
Limits: 100 sections per template, 2,000 blocks per template, 250 templates per site, 50 reusable sections per site, names at most 80 characters.
Section groups: sections/{group}-group.json
The five groups a theme may declare and a layout may render with {% sections 'name' %}: header, footer, announcement, overlay, aside. A group file has exactly the template shape, with type set from its name:
{ "name": "Header", "sections": { "header": { "type": "header" } }, "order": ["header"] }
A theme without a header and a footer group is warned. Groups render inside <div class="ab-section-group ab-section-group--{name}" data-ab-group="{name}">.
locales/
A locale file is a JSON object of strings, nested by dots in the key the t filter reads ('sections.hero.read_more' | t). A plural key is an object with one and other, chosen by the filter's count argument. en.default.json is the fallback; fr.json is what a Canadian French site reads. A theme with no locale file is warned; one without fr.json gets an informational note; a key used in Liquid with no text in the default locale is a warning.
assets/
Everything a page loads: the theme's stylesheet, any script, pictures, fonts, video. {{ 'theme.css' | asset_url }} gives a file's content-versioned address; a name the theme does not have is an error at check time and renders as nothing. A picture whose bytes are not the image its name says is an error (security.mime). What the check reads in CSS, JavaScript and SVG is on The theme check; the budget is on Assets, motion and effects.
screenshots/ and documentation/
Neither is rendered on a site. Screenshots are the pictures the theme library and a listing show; documentation is what a buyer reads — a README.md naming every section and setting, an IMAGES.md with the provenance of every sample picture, and a SAMPLES.json the preview tool uses for sample galleries. A paid theme's requirements for both are on Premium theme standards.