Skip to Content
Getting started

Getting started

Prerequisites

  • Node.js 20+
  • Familiarity with Liquid templating

Two ways to build

A theme is just a directory of files in the layout below, zipped. Nothing about the format requires our tooling, and you never have to install anything to ship a theme:

  1. Build the directory by hand and upload the .zip on the developer portal. Zip it however you like - zip -r my-theme.zip my-theme/, or Finder’s “Compress”. Bundles that nest everything under a wrapper folder are accepted; the platform flattens them on upload.
  2. Use the qm CLI if you have it, for a local preview loop and a pre-flight of the review gate. It is a convenience, not a requirement, and it is distributed to partner developers rather than published on the public npm registry - ask us for access if you want it.

Preview locally with the CLI

qm theme dev # local preview server over your sample-data fixtures qm theme validate # run the review gate's checks before you submit

qm theme dev renders your templates through the same engine the platform runs in production, using the bundled sample-data/*.json fixtures. Open the printed URL and iterate - edit a section, save, refresh.

Local preview, the marketplace preview, and the automated review gate all call the identical render function, so a template that renders in qm theme dev renders in review. Note that this covers the automated checks only - see what validate does not check.

Preview without the CLI

Once a version is published you can render any template over your own fixtures at the public preview endpoint - no auth, no store:

GET /public/themes/<your-slug>/preview/<template>?version=1.0.0

Reviewers use exactly this endpoint against your staged bundle, so it is worth opening each of the seven templates yourself.

Project structure

A theme is a directory with this layout:

my-theme/ ├── theme.json # bundle manifest (name, version, preview image) ├── layout/ │ └── theme.liquid # top-level HTML wrapper for every page ├── templates/ # one .json per page type │ ├── index.json │ ├── product.json │ ├── collection.json │ ├── search.json │ ├── page.json │ ├── wishlist.json │ ├── blog.json │ ├── article.json │ └── 404.json ├── sections/ # *.liquid, each with a {% schema %} block ├── snippets/ # reusable Liquid partials (no schema) ├── config/ │ └── settings_schema.json # global merchant-editable settings ├── assets/ # CSS, JS, fonts, images, screenshots │ ├── common.css # loaded on every page │ ├── theme.css # design tokens / CSS variables │ ├── cart.js # add-to-cart + cart UI behaviour │ └── screenshots/home.png # powers the theme browser tile ├── sample-data/ # dummy data for standalone preview │ ├── shop.json # REQUIRED │ ├── products.json # note the plural - an array │ ├── collections.json # note the plural - an array │ ├── menus.json # main-menu + footer-menu │ ├── search.json │ └── page.json └── locales/ └── en.default.json # optional translations

Required files

Every theme needs all of these. A bundle missing any of them cannot pass review:

  • theme.json - and it must declare a name and a version. Submission is rejected outright without them, because the slug is derived from name.
  • layout/theme.liquid - without it no template can render, so all seven preview renders in the gate fail.
  • config/settings_schema.json - must be a JSON array.
  • sample-data/shop.json - the gate renders every template over your fixtures, and refuses to render anything without a shop. See Preview & sample data.
  • A template for each of the seven preview keys the gate renders: templates/index.json, product.json, collection.json, search.json, page.json, wishlist.json, 404.json.

The last two points are where most first submissions fail. The gate renders index, product, collection, search, page, wishlist and 404 - there is no “optional” template among them. qm theme validate renders the same seven locally, so run it before you submit.

What each piece does

  • theme.json - the manifest. Name, version, tagline, description, and the preview image + screenshots that render on the marketplace tile.
  • layout/theme.liquid - the single HTML shell. Renders <html>, <head>, the header section, {{ content_for_layout }} (where each page’s sections render), and the footer.
  • templates/*.json - which sections appear on each page type, in what order, with what settings. One file per page type.
  • sections/*.liquid - the building blocks. Each ends with a {% schema %} JSON block declaring its merchant-editable settings and blocks.
  • config/settings_schema.json - global theme settings (brand colors, fonts, logo) the merchant edits once and every page reads.
  • assets/ - your CSS, JS, fonts, and images, referenced through the asset_url filter.
  • sample-data/*.json - fixtures used only for previews. Never shipped to a real store, but required: the automated review gate renders every template over them, and shop.json is mandatory.

Next: Theme structure & bundle format.