Theme Folder Structure

Every Shopify theme follows a strict directory structure. Shopify expects specific folders and filenames โ€” there's no flexibility here. This chapter maps every directory, explains every file type, and shows you how the Dawn theme organizes its codebase.

๐Ÿ“Œ Chapter Overview

Time estimate: 30 โ€“ 45 minutes
Tags: Liquid Architecture CSS JavaScript

The Complete Directory Tree

Open your Dawn theme project in VS Code and you'll see this structure. Every Shopify theme โ€” from Dawn to the most complex premium theme โ€” follows this exact layout:

๐Ÿ“ฆ my-shopify-theme/ โ”œโ”€โ”€ ๐Ÿ“‚ assets/ โ† CSS, JS, images, fonts โ”‚ โ”œโ”€โ”€ base.css โ”‚ โ”œโ”€โ”€ component-card.css โ”‚ โ”œโ”€โ”€ global.js โ”‚ โ”œโ”€โ”€ product-form.js โ”‚ โ””โ”€โ”€ logo.png โ”‚ โ”œโ”€โ”€ ๐Ÿ“‚ config/ โ† Theme settings definitions & values โ”‚ โ”œโ”€โ”€ settings_schema.json โ† Settings UI definition โ”‚ โ””โ”€โ”€ settings_data.json โ† Saved setting values (auto-generated) โ”‚ โ”œโ”€โ”€ ๐Ÿ“‚ layout/ โ† Outermost HTML shell โ”‚ โ”œโ”€โ”€ theme.liquid โ† Main layout (every page) โ”‚ โ””โ”€โ”€ password.liquid โ† Password protection page layout โ”‚ โ”œโ”€โ”€ ๐Ÿ“‚ locales/ โ† Translation files โ”‚ โ”œโ”€โ”€ en.default.json โ† English (default) โ”‚ โ”œโ”€โ”€ fr.json โ”‚ โ””โ”€โ”€ es.json โ”‚ โ”œโ”€โ”€ ๐Ÿ“‚ sections/ โ† Modular page components โ”‚ โ”œโ”€โ”€ header.liquid โ”‚ โ”œโ”€โ”€ footer.liquid โ”‚ โ”œโ”€โ”€ announcement-bar.liquid โ”‚ โ”œโ”€โ”€ main-product.liquid โ”‚ โ”œโ”€โ”€ main-collection.liquid โ”‚ โ”œโ”€โ”€ featured-collection.liquid โ”‚ โ”œโ”€โ”€ image-banner.liquid โ”‚ โ”œโ”€โ”€ rich-text.liquid โ”‚ โ”œโ”€โ”€ header-group.json โ† Section group โ”‚ โ””โ”€โ”€ footer-group.json โ† Section group โ”‚ โ”œโ”€โ”€ ๐Ÿ“‚ snippets/ โ† Reusable code fragments โ”‚ โ”œโ”€โ”€ product-card.liquid โ”‚ โ”œโ”€โ”€ price.liquid โ”‚ โ”œโ”€โ”€ icon-cart.liquid โ”‚ โ””โ”€โ”€ meta-tags.liquid โ”‚ โ””โ”€โ”€ ๐Ÿ“‚ templates/ โ† Page type definitions โ”œโ”€โ”€ index.json โ† Homepage โ”œโ”€โ”€ product.json โ† Product page โ”œโ”€โ”€ collection.json โ† Collection page โ”œโ”€โ”€ list-collections.json โ”œโ”€โ”€ page.json โ† Custom page โ”œโ”€โ”€ blog.json โ”œโ”€โ”€ article.json โ”œโ”€โ”€ cart.json โ”œโ”€โ”€ search.json โ”œโ”€โ”€ 404.json โ”œโ”€โ”€ page.contact.json โ† Alternate template โ”œโ”€โ”€ gift_card.liquid โ† Special Liquid template โ”œโ”€โ”€ password.json โ””โ”€โ”€ ๐Ÿ“‚ customers/ โ† Customer account pages โ”œโ”€โ”€ account.liquid โ”œโ”€โ”€ login.liquid โ”œโ”€โ”€ register.liquid โ”œโ”€โ”€ order.liquid โ”œโ”€โ”€ addresses.liquid โ”œโ”€โ”€ activate_account.liquid โ””โ”€โ”€ reset_password.liquid
โš ๏ธ No Custom Folders Allowed

Shopify only recognizes these specific directories. You cannot create custom folders like components/ or partials/. All reusable code goes in snippets/. All static files go in assets/. This is a hard platform constraint.

The assets/ Directory

The assets/ folder contains all static files: CSS, JavaScript, images, fonts, and SVGs. This is a flat directory โ€” no subdirectories are allowed.

Naming Conventions

Since you can't use subdirectories, use naming prefixes to organize your files. Here's the pattern Dawn uses:

Prefix Purpose Examples
base-* Foundation styles (reset, typography, variables) base.css
component-* Reusable UI component styles component-card.css, component-badge.css
section-* Section-specific styles section-featured-collection.css
template-* Template-specific styles template-product.css
global.* Global JavaScript functionality global.js
product-* Product-related JS modules product-form.js, product-modal.js

CSS Organization Strategy

Dawn splits CSS into many small files and loads them conditionally. This is a performance optimization โ€” pages only load the CSS they need:

Conditional CSS Loading in a Section
{%- comment -%}
  Only load this CSS file when this section is present on the page.
  This avoids loading unnecessary CSS on pages that don't use this section.
{%- endcomment -%}

{{ 'section-featured-collection.css' | asset_url | stylesheet_tag }}
{{ 'component-card.css' | asset_url | stylesheet_tag }}

<section class="featured-collection">
  {%- for product in section.settings.collection.products limit: 4 -%}
    {% render 'product-card', product: product %}
  {%- endfor -%}
</section>
โœ… Best Practice โ€” CSS Architecture

Split your CSS into logical files rather than one massive stylesheet. Use prefix naming to keep them organized. Load section-specific CSS at the top of each section file. This keeps unused CSS off pages that don't need it and improves load times.

JavaScript Organization

Dawn uses vanilla JavaScript with Web Components and custom elements. JS files follow the same flat structure:

Loading JS in a Section
<!-- Deferred loading for non-critical JavaScript -->
<script src="{{ 'product-form.js' | asset_url }}" defer="defer"></script>

<!-- Or conditionally load based on section presence -->
{%- if section.settings.enable_slideshow -%}
  <script src="{{ 'slideshow.js' | asset_url }}" defer="defer"></script>
{%- endif -%}

Image and Font Files

Static images (logos, icons, backgrounds) and custom font files also go in assets/:

Referencing Static Assets
<!-- Logo image -->
<img src="{{ 'logo.png' | asset_url }}" alt="{{ shop.name }}">

<!-- SVG icon -->
<img src="{{ 'icon-cart.svg' | asset_url }}" alt="" width="20" height="20">

<!-- Custom font in CSS -->
@font-face {
  font-family: 'MyCustomFont';
  src: url('{{ "my-font.woff2" | asset_url }}') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
๐Ÿ’ก SVG Icons as Snippets

Instead of storing SVG icons as image files, many professional themes store them as Liquid snippets. This lets you inline SVGs for better performance and CSS styling control. Create files like snippets/icon-cart.liquid containing the raw SVG code, then use {% render 'icon-cart' %}.

The config/ Directory

The config/ directory contains exactly two files that control theme-wide settings:

settings_schema.json

This file defines the UI for global theme settings. It specifies what settings appear in the theme editor under "Theme settings" and how they're organized into groups.

config/settings_schema.json (structure)
[
  {
    "name": "theme_info",
    "theme_name": "My Custom Theme",
    "theme_version": "1.0.0",
    "theme_author": "Gamal",
    "theme_documentation_url": "https://example.com/docs",
    "theme_support_url": "https://example.com/support"
  },
  {
    "name": "Colors",
    "settings": [
      {
        "type": "header",
        "content": "Primary Colors"
      },
      {
        "type": "color",
        "id": "color_primary",
        "label": "Primary brand color",
        "default": "#6366f1",
        "info": "Used for buttons, links, and accents"
      },
      {
        "type": "color",
        "id": "color_text",
        "label": "Text color",
        "default": "#1a1a2e"
      },
      {
        "type": "color",
        "id": "color_background",
        "label": "Page background",
        "default": "#ffffff"
      }
    ]
  },
  {
    "name": "Typography",
    "settings": [
      {
        "type": "font_picker",
        "id": "font_heading",
        "label": "Heading font",
        "default": "helvetica_n7"
      },
      {
        "type": "font_picker",
        "id": "font_body",
        "label": "Body font",
        "default": "helvetica_n4"
      },
      {
        "type": "range",
        "id": "font_body_scale",
        "label": "Body font size scale",
        "min": 80,
        "max": 130,
        "step": 5,
        "default": 100,
        "unit": "%"
      }
    ]
  },
  {
    "name": "Social media",
    "settings": [
      {
        "type": "header",
        "content": "Social accounts"
      },
      {
        "type": "text",
        "id": "social_twitter_link",
        "label": "Twitter",
        "info": "https://twitter.com/your-handle"
      },
      {
        "type": "text",
        "id": "social_instagram_link",
        "label": "Instagram"
      },
      {
        "type": "text",
        "id": "social_facebook_link",
        "label": "Facebook"
      }
    ]
  },
  {
    "name": "Favicon",
    "settings": [
      {
        "type": "image_picker",
        "id": "favicon",
        "label": "Favicon image",
        "info": "32 x 32px .png recommended"
      }
    ]
  }
]

settings_data.json

This file stores the actual values that merchants have set through the theme editor. It's auto-generated and should rarely be edited manually.

config/settings_data.json (auto-generated excerpt)
{
  "current": {
    "color_primary": "#6366f1",
    "color_text": "#1a1a2e",
    "color_background": "#ffffff",
    "font_heading": "helvetica_n7",
    "font_body": "helvetica_n4",
    "font_body_scale": 100,
    "social_twitter_link": "https://twitter.com/shopify",
    "social_instagram_link": "https://instagram.com/shopify",
    "sections": {
      "header": {
        "type": "header",
        "settings": {
          "logo_position": "middle-center"
        }
      }
    }
  }
}
๐Ÿšจ Careful with settings_data.json

This file contains the merchant's customizations. If you're working on a client's store and you push your local settings_data.json, it could overwrite their settings. Use the --ignore flag when pushing: shopify theme push --ignore config/settings_data.json

The layout/ Directory

The layout directory typically contains two files:

File Purpose Used By
theme.liquid Main layout for all pages. Contains <html>, <head>, header, footer, and {{ content_for_layout }}. Every page except password page
password.liquid Layout for the password protection page shown when the store isn't public yet. Store password page only

Anatomy of theme.liquid

layout/theme.liquid (annotated)
<!doctype html>
<html class="no-js" lang="{{ request.locale.iso_code }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <!-- Page title with store name -->
  <title>
    {{ page_title }}
    {%- if current_tags %} &ndash; tagged "{{ current_tags | join: ', ' }}"{% endif -%}
    {%- if current_page != 1 %} &ndash; Page {{ current_page }}{% endif -%}
    {%- unless page_title contains shop.name %} &ndash; {{ shop.name }}{% endunless -%}
  </title>

  <!-- SEO meta tags -->
  {%- if page_description -%}
    <meta name="description" content="{{ page_description | escape }}">
  {%- endif -%}

  <!-- Canonical URL -->
  <link rel="canonical" href="{{ canonical_url }}">

  <!-- REQUIRED: Shopify analytics, apps, meta tags -->
  {{ content_for_header }}

  <!-- Theme CSS variables from settings -->
  {%- style -%}
    :root {
      --color-primary: {{ settings.color_primary }};
      --color-text: {{ settings.color_text }};
      --color-background: {{ settings.color_background }};
      --font-heading-family: {{ settings.font_heading.family }},
        {{ settings.font_heading.fallback_families }};
      --font-body-family: {{ settings.font_body.family }},
        {{ settings.font_body.fallback_families }};
    }
  {%- endstyle -%}

  <!-- Base stylesheet -->
  {{ 'base.css' | asset_url | stylesheet_tag }}

  <!-- Preload critical fonts -->
  <link rel="preconnect" href="https://fonts.shopifycdn.com" crossorigin>

  <!-- Favicon -->
  {%- if settings.favicon -%}
    <link rel="icon" type="image/png"
          href="{{ settings.favicon | image_url: width: 32, height: 32 }}">
  {%- endif -%}

  <!-- No-JS detection -->
  <script>
    document.documentElement.className =
      document.documentElement.className.replace('no-js', 'js');
  </script>
</head>

<body class="template-{{ template.name }}">
  <a class="skip-to-content-link" href="#MainContent">
    {{ 'accessibility.skip_to_content' | t }}
  </a>

  {%- sections 'header-group' -%}

  <main id="MainContent" class="content-for-layout" role="main"
        tabindex="-1">
    {{ content_for_layout }}
  </main>

  {%- sections 'footer-group' -%}

  <!-- Global JavaScript -->
  <script src="{{ 'global.js' | asset_url }}" defer="defer"></script>
</body>
</html>
๐Ÿ’ก Study This File Carefully

The theme.liquid file is the most important file in any theme. Study Dawn's version line by line. Pay attention to the SEO meta tags, the skip-to-content link for accessibility, the CSS variable bridge from settings, and the font preloading. Every line serves a purpose.

The templates/ Directory

Templates define which sections appear on each page type. In Online Store 2.0, templates are JSON files.

Required Template Types

Template Page Type Main Object Available
index.json Homepage shop
product.json Product detail page product
collection.json Collection page collection
list-collections.json All collections page collections
page.json Custom content page page
blog.json Blog listing page blog
article.json Blog article page article
cart.json Cart page cart
search.json Search results page search
404.json 404 error page โ€”
password.json Store password page โ€”
gift_card.liquid Gift card page gift_card

Anatomy of a JSON Template

templates/index.json (Homepage)
{
  "sections": {
    "image_banner": {
      "type": "image-banner",
      "settings": {
        "image": "shopify://shop_images/hero.jpg",
        "heading": "Welcome to Our Store",
        "heading_size": "h1",
        "button_label": "Shop Now",
        "button_link": "shopify://collections/all"
      }
    },
    "featured_collection": {
      "type": "featured-collection",
      "settings": {
        "heading": "Featured Products",
        "collection": "frontpage",
        "products_to_show": 8
      }
    },
    "rich_text": {
      "type": "rich-text",
      "settings": {
        "heading": "About Our Brand",
        "text": "<p>We create premium products...</p>"
      }
    }
  },
  "order": [
    "image_banner",
    "featured_collection",
    "rich_text"
  ]
}

Understanding the structure:

  • "sections" โ€” Object containing all sections. Each key is a unique ID you define.
  • "type" โ€” References a file in sections/ (without .liquid extension).
  • "settings" โ€” Pre-set values matching the section's schema settings.
  • "order" โ€” Array defining the display order of sections.

Alternate Templates

Create alternate templates by adding a suffix after a dot:

๐Ÿ“‚ templates/ โ”œโ”€โ”€ product.json โ† Default product template โ”œโ”€โ”€ product.with-video.json โ† Alternate: "with-video" โ”œโ”€โ”€ product.minimal.json โ† Alternate: "minimal" โ”œโ”€โ”€ page.json โ† Default page template โ”œโ”€โ”€ page.contact.json โ† Alternate: "contact" โ””โ”€โ”€ page.faq.json โ† Alternate: "faq"

Merchants assign alternate templates to specific products or pages in the Shopify admin. This is how a store can have different layouts for different product types.

Customer Templates

Customer account pages still use Liquid templates (not JSON) because they have special form requirements:

๐Ÿ“‚ templates/customers/ โ”œโ”€โ”€ account.liquid โ† My account dashboard โ”œโ”€โ”€ login.liquid โ† Login form โ”œโ”€โ”€ register.liquid โ† Registration form โ”œโ”€โ”€ order.liquid โ† Order detail page โ”œโ”€โ”€ addresses.liquid โ† Manage addresses โ”œโ”€โ”€ activate_account.liquid โ† Account activation โ””โ”€โ”€ reset_password.liquid โ† Password reset

The sections/ Directory

This is where most of your development work happens. Each file in sections/ is a self-contained module with markup, optional CSS/JS, and a schema.

Section Naming Conventions

Prefix Purpose Examples
main-* Primary content section for a page type. Usually renders the core page-specific object. main-product.liquid, main-collection.liquid, main-cart.liquid
(no prefix) Reusable sections that can be added to any page through the theme editor. featured-collection.liquid, image-banner.liquid, rich-text.liquid
*-group.json Section groups that appear on every page (header, footer). header-group.json, footer-group.json

Section File Anatomy

sections/example-section.liquid (complete anatomy)
{%- comment -%}
  PART 1: CSS Loading
  Load section-specific CSS only when this section is used
{%- endcomment -%}
{{ 'section-example.css' | asset_url | stylesheet_tag }}

{%- comment -%}
  PART 2: Liquid Markup (HTML)
  The visual output of the section
{%- endcomment -%}
<section
  id="section-{{ section.id }}"
  class="example-section color-{{ section.settings.color_scheme }}"
>
  <div class="page-width">
    {%- if section.settings.heading != blank -%}
      <h2 class="example-section__heading">
        {{ section.settings.heading }}
      </h2>
    {%- endif -%}

    {%- for block in section.blocks -%}
      <div class="example-section__block" {{ block.shopify_attributes }}>
        {% case block.type %}
          {% when 'text' %}
            <p>{{ block.settings.text }}</p>
          {% when 'image' %}
            <img src="{{ block.settings.image | image_url: width: 600 }}"
                 alt="{{ block.settings.image.alt | escape }}">
        {% endcase %}
      </div>
    {%- endfor -%}
  </div>
</section>

{%- comment -%}
  PART 3: Schema (JSON)
  Defines settings, blocks, and presets for the theme editor
{%- endcomment -%}
{% schema %}
{
  "name": "Example Section",
  "tag": "section",
  "class": "section",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Section Heading"
    },
    {
      "type": "select",
      "id": "color_scheme",
      "label": "Color scheme",
      "options": [
        { "value": "light", "label": "Light" },
        { "value": "dark", "label": "Dark" }
      ],
      "default": "light"
    }
  ],
  "blocks": [
    {
      "type": "text",
      "name": "Text Block",
      "settings": [
        {
          "type": "richtext",
          "id": "text",
          "label": "Text",
          "default": "<p>Share your story...</p>"
        }
      ]
    },
    {
      "type": "image",
      "name": "Image Block",
      "settings": [
        {
          "type": "image_picker",
          "id": "image",
          "label": "Image"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "Example Section",
      "blocks": [
        { "type": "text" },
        { "type": "image" }
      ]
    }
  ]
}
{% endschema %}
๐Ÿ’ก The Presets Key

The "presets" array in the schema is what makes a section available in the "Add section" menu of the theme editor. Without presets, a section can only be used if it's already referenced in a JSON template. Sections like main-product typically don't have presets because they're always present on their respective page type.

The snippets/ Directory

Snippets are reusable Liquid fragments. They're included using {% render 'snippet-name' %}. Snippets have no schema โ€” they receive all their data through explicitly passed variables.

Common Snippets in Dawn

Snippet Purpose
product-card.liquid Renders a product card (used in collection grids, featured collections, search results)
price.liquid Renders price display with sale/compare-at logic
icon-*.liquid Inline SVG icons (cart, search, menu, close, etc.)
meta-tags.liquid SEO meta tags, Open Graph, Twitter cards
cart-notification.liquid Ajax cart notification popup
header-search.liquid Search form component used in header

Well-Structured Snippet Pattern

snippets/product-card.liquid (documented pattern)
{%- comment -%}
  ============================================================
  Product Card Snippet
  ============================================================

  Renders a product card for grids and carousels.

  Accepts:
  - product:        {Object}  Product Liquid object (required)
  - show_vendor:    {Boolean} Display vendor name (default: false)
  - show_rating:    {Boolean} Display star rating (default: false)
  - image_ratio:    {String}  Image aspect ratio: 'square', 'portrait',
                              'landscape', 'adapt' (default: 'adapt')
  - lazy_load:      {Boolean} Lazy-load the image (default: true)
  - card_class:     {String}  Additional CSS class (default: '')

  Usage:
  {% render 'product-card',
    product: product,
    show_vendor: true,
    image_ratio: 'square',
    lazy_load: forloop.index > 4
  %}

  Dependencies:
  - component-card.css
  - snippets/price.liquid
  ============================================================
{%- endcomment -%}

{%- liquid
  assign lazy = lazy_load | default: true
  assign ratio = image_ratio | default: 'adapt'
  assign show_vendor_name = show_vendor | default: false
-%}

<div class="product-card {{ card_class }}">
  <a href="{{ product.url }}" class="product-card__link"
     aria-label="{{ product.title | escape }}">

    <!-- Image -->
    <div class="product-card__media product-card__media--{{ ratio }}">
      {%- if product.featured_image -%}
        <img
          src="{{ product.featured_image | image_url: width: 600 }}"
          srcset="
            {{ product.featured_image | image_url: width: 300 }} 300w,
            {{ product.featured_image | image_url: width: 450 }} 450w,
            {{ product.featured_image | image_url: width: 600 }} 600w
          "
          sizes="(max-width: 749px) calc(50vw - 30px), 300px"
          alt="{{ product.featured_image.alt | escape }}"
          width="{{ product.featured_image.width }}"
          height="{{ product.featured_image.height }}"
          {% if lazy %}loading="lazy" decoding="async"{% endif %}
        >
      {%- else -%}
        {{ 'product-1' | placeholder_svg_tag: 'product-card__placeholder' }}
      {%- endif -%}
    </div>

    <!-- Info -->
    <div class="product-card__info">
      {%- if show_vendor_name and product.vendor != blank -%}
        <span class="product-card__vendor">{{ product.vendor }}</span>
      {%- endif -%}

      <h3 class="product-card__title">{{ product.title | escape }}</h3>

      {% render 'price', product: product %}
    </div>
  </a>
</div>
โœ… Best Practice โ€” Document Your Snippets

Always add a comment block at the top of every snippet listing: what it renders, what variables it accepts (with types and defaults), usage examples, and CSS dependencies. This is how professional theme developers work. When you revisit code months later โ€” or when another developer reads it โ€” this documentation is invaluable.

The locales/ Directory

The locales/ directory contains translation files. Even if your theme only supports English, you should use the locales system for all user-facing strings.

locales/en.default.json (excerpt)
{
  "general": {
    "search": "Search",
    "close": "Close",
    "loading": "Loading..."
  },
  "products": {
    "product": {
      "add_to_cart": "Add to cart",
      "sold_out": "Sold out",
      "unavailable": "Unavailable",
      "price": {
        "from": "From {{ price }}",
        "sale_price": "Sale price",
        "regular_price": "Regular price"
      }
    }
  },
  "cart": {
    "general": {
      "title": "Your cart",
      "empty": "Your cart is empty",
      "continue_shopping": "Continue shopping"
    }
  },
  "accessibility": {
    "skip_to_content": "Skip to content",
    "close": "Close"
  }
}

Access translations in Liquid using the t filter:

Using Translations
<!-- Simple translation -->
<button>{{ 'products.product.add_to_cart' | t }}</button>
<!-- Output: Add to cart -->

<!-- Translation with variable -->
<span>{{ 'products.product.price.from' | t: price: product.price | money }}</span>
<!-- Output: From $25.00 -->

<!-- Accessibility label -->
<a href="#MainContent">{{ 'accessibility.skip_to_content' | t }}</a>
โœ… Why Use Translations Even for Single-Language Themes?

1. Future-proofing: Adding languages later is trivial โ€” just add new JSON files.
2. Merchant control: Merchants can edit text through the theme editor language settings without touching code.
3. Consistency: All strings are in one place, making it easy to find and update wording.
4. Theme Store requirement: Shopify requires translations for themes submitted to the Theme Store.

Dawn File-by-File Walkthrough

Let's walk through the most important files in Dawn to understand how a real theme connects everything:

1

layout/theme.liquid

Open this file first. Notice the CSS custom properties generated from settings, the content_for_header placement, and how section groups are rendered for header and footer.

2

templates/index.json

See how the homepage is composed from sections. Each section reference in the "sections" object corresponds to a file in sections/.

3

sections/image-banner.liquid

Study this section's schema. See how it defines settings for the image, heading, button text, and button link. Notice the blocks for flexible content arrangement.

4

sections/main-product.liquid

This is the most complex section in Dawn. Study how it uses blocks for the product form layout โ€” title, price, variant picker, quantity selector, buy button, and description are all individual blocks.

5

snippets/product-card.liquid

See how this snippet is used in multiple sections (featured collection, search results, product recommendations). Notice the variable parameters it accepts and how it handles missing images.

6

config/settings_schema.json

Explore how Dawn organizes global settings into logical groups: colors, typography, social media, favicon, layout. Notice the info fields that help merchants understand each setting.

Exercise: Explore Your Dawn Theme

๐Ÿงช
Hands-On Exercise

Theme Structure Exploration

โฑ๏ธ 20 minutes ๐Ÿ“ All directories

Objective: Build a mental map of how Dawn's files connect to each other.

Tasks:

  1. Open templates/index.json. List all the section types referenced.
  2. For each section type, find the corresponding .liquid file in sections/.
  3. Open sections/featured-collection.liquid. Find every {% render %} call and note which snippets it uses.
  4. Open those snippets in snippets/ and trace how data flows from section โ†’ snippet.
  5. Count how many CSS files are in assets/. How many JS files?
  6. Open config/settings_schema.json. How many setting groups are there? How many individual settings?
  7. Open locales/en.default.json. Find the translation key for the "Add to cart" button text.

Learning goal: You should be able to trace any visual element on the storefront back to its source file in the theme.

Key Takeaways

  • Shopify themes have a strict folder structure โ€” no custom directories allowed
  • assets/ is flat โ€” use naming prefixes to organize files
  • config/ has two files: schema (definition) and data (saved values)
  • layout/theme.liquid is the outermost HTML shell for every page
  • templates/ are JSON files defining which sections appear on each page type
  • Alternate templates use dot-suffix naming: product.special.json
  • sections/ contain modular components with markup, CSS, JS, and schema
  • snippets/ contain reusable Liquid fragments โ€” always document their parameters
  • locales/ hold translations โ€” use them even for single-language themes
  • CSS should be split into small, conditionally-loaded files for performance