Skip to content

Getting started: build a theme

This guide takes you end to end: you’ll create a theme, add a working section the visual editor can place, wire up a setting and a block, pull in an asset and a snippet, then preview your change as a private draft and publish it. By the end you’ll understand how a Sellerlane theme’s files fit together and how the draft-then-publish model protects your live store.

It assumes you’re comfortable editing code. If you only want to rearrange and configure what a theme already ships, the drag-and-drop visual editor is the place to start instead.

Before you begin: the file structure

A theme is a folder of files that the storefront renders for every page. You edit them in the code editor (Edit code). The folders are fixed:

FolderHolds
layout/theme.liquid — the wrapper for every page
templates/One file per page type (index.json, product.json, …)
sections/Reusable section files with a {% schema %}, plus section-group files (header.json, footer.json)
blocks/Reusable theme blocks with their own schema
snippets/Partials included with {% render %}
assets/CSS, JS, images, fonts — referenced with asset_url
config/settings_schema.json and settings_data.json (global settings)
locales/Translation files for the t filter

For the full breakdown — how a page assembles, JSON vs Liquid templates, the recognised template types — read Theme architecture first.

1. Create or open a theme

You have two starting points.

  1. Open Online store → Themes.

  2. On the theme you want to work on, choose Edit code. The code editor opens on that theme’s draft with the file tree on the left.

Editing code never touches the live store — every change lands in the draft until you publish.

2. Add a section with a schema and a preset

A section is a reusable, configurable band of a page. The visual editor can only add a section that declares a preset — without one, the section is reachable from code only.

  1. In the file tree, click the + on the Sections folder. Choose the Liquid format and name it hello (lowercase letters, numbers, hyphens, and underscores only). The editor creates sections/hello.liquid.

  2. Paste a minimal section with markup and a {% schema %}:

    <div class="hello" {{ section.shopify_attributes }}>
    <h2>{{ section.settings.heading }}</h2>
    </div>
    {% schema %}
    {
    "name": "Hello",
    "tag": "section",
    "settings": [
    { "type": "text", "id": "heading", "label": "Heading", "default": "Hello there" }
    ],
    "presets": [{ "name": "Hello" }]
    }
    {% endschema %}
  3. Press Save (Ctrl/Cmd + S). The schema is validated on save — an invalid schema blocks the save with a specific error.

The presets array is what makes the section addable. Now open the visual editor, use Add section, and your Hello section appears in the picker. Add it to the home page and you’ll see Hello there render.

3. Wire a setting and render it

The setting you added (heading) is already wired: the schema declares it under settings, and the markup reads it with {{ section.settings.heading }}. The pattern is always the two halves matching:

  • Declare the input in settings with an id, a type, and a label.
  • Read it in the body as section.settings.<id>.

Add a second setting — a checkbox — to see the loop end to end:

<div class="hello" {{ section.shopify_attributes }}>
<h2>{{ section.settings.heading }}</h2>
{% if section.settings.show_subtitle %}
<p>Welcome to the store.</p>
{% endif %}
</div>
{% schema %}
{
"name": "Hello",
"tag": "section",
"settings": [
{ "type": "text", "id": "heading", "label": "Heading", "default": "Hello there" },
{ "type": "checkbox", "id": "show_subtitle", "label": "Show subtitle", "default": true }
],
"presets": [{ "name": "Hello" }]
}
{% endschema %}

Save, and the editor’s inspector now shows a Heading field and a Show subtitle toggle for any Hello section. text, richtext, color, image_picker, collection, product, range, and many more input types are available — see Setting types. Many text and resource settings can also bind to dynamic sources so a value pulls from a product field or metafield automatically.

4. Add a block

A block is a smaller, repeatable unit inside a section that merchants can add, reorder, and configure. There are two kinds, and a section uses one or the other — never both.

The simplest is a local (section-defined) block: declared inline in the section’s blocks array and rendered by looping section.blocks.

<div class="hello" {{ section.shopify_attributes }}>
<h2>{{ section.settings.heading }}</h2>
<ul>
{% for block in section.blocks %}
{% case block.type %}
{% when 'point' %}
<li {{ block.shopify_attributes }}>{{ block.settings.text }}</li>
{% endcase %}
{% endfor %}
</ul>
</div>
{% schema %}
{
"name": "Hello",
"tag": "section",
"settings": [
{ "type": "text", "id": "heading", "label": "Heading", "default": "Hello there" }
],
"blocks": [
{ "type": "point", "name": "Point", "settings": [
{ "type": "text", "id": "text", "label": "Text" }
]}
],
"max_blocks": 6,
"presets": [{ "name": "Hello" }]
}
{% endschema %}

Save, reopen the section in the editor, and the + on the section now offers a Point block you can add up to six times.

For reusable theme blocks (files in blocks/, opted into with { "type": "@theme" } and rendered with {% content_for 'blocks' %} instead of a for loop), see Theme blocks. A single section can’t mix local blocks with theme blocks.

5. Use an asset and a snippet

Assets are the files in assets/ — CSS, JS, images, fonts. Reference one with the asset_url filter, which returns a versioned, CDN-served URL so each published version is cached immutably.

  1. In the code editor, open the Assets folder, choose +, and Create blank assetCSS, named hello.css. Add a rule:

    .hello { text-align: center; padding: 2rem; }
  2. In sections/hello.liquid, load it with the stylesheet_tag filter, which wraps the URL in a <link>:

    {{ 'hello.css' | asset_url | stylesheet_tag }}

Snippets are partials in snippets/ that you reuse across sections with {% render %}. A snippet runs in an isolated scope — it sees only the variables you pass in.

  1. Create snippets/badge.liquid:

    <span class="badge">{{ label }}</span>
  2. Render it from the section, passing the variable explicitly:

    {% render 'badge', label: section.settings.heading %}

6. Preview as a draft, then publish

Everything so far lives in the draft. The draft is private to you and your staff — shoppers never see it.

  1. Save every file you changed. Only saved draft content is included when you publish.

  2. From Online store → Themes, choose Preview on the theme (or Preview in the editor’s top bar) to open the draft in a new tab without going live. Click through your pages and confirm the section, settings, blocks, and styles look right.

  3. When you’re happy, choose Publish in the editor’s top bar. In the Publish theme dialog, optionally add a Release label (for example Summer update) so you can identify the snapshot later, then confirm.

Publishing creates a new live version from your saved draft and switches the storefront to it. The draft stays editable, so you can keep working immediately.

How versioning protects the live store

Every theme version carries one of three statuses — DRAFT, LIVE, or ARCHIVED:

  • You only ever edit a draft, so unfinished work can’t leak to shoppers.
  • Publishing promotes the draft to a numbered, immutable LIVE version and demotes the previous live one to ARCHIVED.
  • Because published versions are immutable snapshots, you can roll back instantly: open Online store → Themes, expand View versions, and choose Make live (or Set live) on an earlier version. No re-editing required.

Asset URLs are pinned to the version too — a live request serves the live version’s assets from the CDN, while a verified editor preview serves the draft’s assets with no-cache headers — so a publish swaps the whole bundle atomically and a rollback restores the exact files that shipped. See Manage themes for the full version lifecycle.

Next steps

You’ve built a section, wired settings and a block, and shipped it safely. From here:

Theme blocks

Build reusable, nestable blocks any section can host — Theme blocks.

Section groups

Share the header, footer, and aside bands across every page — Section groups.

Reference: Theme architecture · Section schema · Setting types · Theme assets (CSS/JS) · Dynamic sources · Liquid objects · Liquid tags · Liquid filters

Related: Editing theme code · Themes & the visual editor · Import a theme ZIP · Manage themes