Skip to content
Ecom

Shopify Theme File Structure Explained for First-Time Devs

A beginner-friendly map of the Shopify theme folder structure: sections, templates, snippets, assets, locales, config. What each folder is for, where to look when something breaks, and the file we...

By WitsCode10 min read

The first time you unzip a Shopify theme and stare at the folder tree, it looks like someone took a small Rails app, removed the familiar parts, and renamed everything. Eight or nine folders, JSON and Liquid files mixed together, a config folder with two files that look almost identical but do entirely different jobs, and a blocks directory that half the tutorials on the internet do not even mention because it did not exist eighteen months ago.

This guide walks through that tree the way we walk a new developer through it on their first day at WitsCode. We build on Shopify's own Dawn theme as the reference, because Dawn is what Shopify ships as the OS 2.0 baseline and what most modern custom themes are forked from or modelled on. By the end you will know what each folder is for, which file Shopify renders first when a customer hits a URL, and which file we open within sixty seconds of starting almost every client project.

The Thirty-Second Mental Model

Before the folders, the rendering chain. When a shopper visits /products/navy-hoodie, Shopify's server does four things in order. It picks a template based on the URL (the product template, in this case). It wraps that template in a layout (almost always theme.liquid). It reads any section groups the layout references (the header group, the footer group). And it resolves all the settings the merchant has saved for those sections and blocks, pulled from the config files.

Every folder in the theme exists to feed one of those four stages. layout/ feeds stage two. templates/ feeds stage one. sections/ and blocks/ feed stage three. snippets/ are the small reusable pieces those sections call. config/ feeds stage four. assets/ serves the CSS, JS, and images referenced along the way. locales/ provides the translated strings. That is the whole system. Every time a file feels confusing, ask which of those four stages it serves and the confusion usually clears.

One more frame before we open any folders. Shopify themes are not a framework you run. They are a set of files Shopify's servers render on every request. Your JavaScript and CSS ship to the browser, but your Liquid never does. All the logic inside {% %} tags runs server-side before the HTML leaves Shopify's CDN. This changes what "performance" means for a theme developer: your bottleneck is usually Liquid render time, not bundle size.

Layout and Templates, the Rendering Chain

layout/theme.liquid is the outermost shell of every page on the store. It contains the <html>, <head>, and <body> tags, and exactly two Liquid outputs that matter. The first is {{ content_for_header }}, which Shopify injects with analytics scripts, font preloads, the consent banner, app script tags, and a dozen other things the platform controls. You never remove it. If you do, half the admin stops working and the store fails review. The second is {{ content_for_layout }}, which is where the page-specific template renders. Everything else in theme.liquid is yours: global header, global footer, meta tags, skip-to-content links, cart drawer markup, modal containers.

Older themes hard-coded the header and footer with {% section 'header' %} and {% section 'footer' %}. Modern themes use section groups instead. You will see {% sections 'header-group' %} (note the plural, note the hyphen) pointing at sections/header-group.json, a JSON file that lists every section the merchant has placed in the header area and the order they appear. This matters because it lets merchants add announcement bars, search bars, and custom sections above or below the header directly from the theme editor, without a developer touching code. If you are building a custom theme in 2026 and still hard-coding the header, you are shipping 2021.

The second layout file you may see is password.liquid, used when the store is in password-protected mode. You rarely touch it. The old checkout.liquid is gone for every store on Checkout Extensibility, which is all stores on Plus and, since 2024, all stores full stop.

Templates live in templates/. There is one template per resource type: product.json, collection.json, index.json (the homepage), cart.json, search.json, 404.json, page.json, blog.json, article.json. Customer pages live under templates/customers/ (login, register, account, order, addresses). Metaobject landing pages, if the store uses them, live under templates/metaobject/.

The important thing about templates is that they come in two flavours and you almost always want the JSON version. A JSON template is just an ordered list of sections with their saved settings. The merchant can add, remove, and reorder those sections from the theme editor. A Liquid template is the old format, code-only, merchant-locked. New themes ship JSON templates for every resource. The only time you use a Liquid template is when you have a custom page that genuinely should not be merchant-editable, and even that is rare.

Templates also support alternate versions. product.bundle.json gives you a second product template called "bundle" that merchants can assign to specific products in the admin. Same for collections and pages. This is how you give merchants multiple layouts for different product types without forking the whole theme.

Sections, Snippets, and the New Blocks Folder

sections/ is where the actual page content lives. A section is a Liquid file with a {% schema %} block at the bottom, and that schema block is what makes the section editable. The schema defines the section's name in the editor, the settings (text inputs, colour pickers, image pickers, range sliders, all the UI controls), the blocks it can contain, and presets for adding it to templates. Understanding section schema is probably the single biggest unlock for a junior Shopify developer, because once you can write a schema, you can expose any design decision you made as a knob the merchant can turn.

Section groups, the JSON files in the same folder like header-group.json and footer-group.json, are a separate concept and worth restating because most tutorials still skip them. A section group is not a section. It is a container, referenced from the layout, that lets merchants stack multiple sections in the header or footer area. The JSON file lists section types and their settings. Merchants edit it through the theme editor the same way they edit a page template.

snippets/ holds the small reusable Liquid fragments that sections call. Snippets have no schema. They are just Liquid. You render them with {% render 'card-product', product: featured_product %}. The important detail for new developers is that render gives the snippet an isolated scope. It cannot see variables from the parent section unless you pass them explicitly. The old {% include %} tag shared scope but is deprecated, and if you see it in a codebase, that codebase is old. Always use render. Always pass variables explicitly. It makes snippets predictable and testable, and it lets Shopify cache them more aggressively.

blocks/ is the folder most beginner guides do not cover, because it only arrived with the Theme Blocks feature in 2024. Traditional section blocks are declared inside a specific section's schema, which means if you want the same block in three sections, you declare it three times. Theme Blocks break that pattern. A file in blocks/ is a reusable block with its own schema, its own template, and can be nested inside any section that opts into accepting it. It can also be nested inside other blocks. This is the architecture that lets third-party app developers ship blocks that drop into any compatible section without the section author knowing about them. If you are building a theme in 2026, invest an afternoon understanding theme blocks. They change how you structure reusable components and they are where Shopify's theme architecture is heading.

Config, the Schema Versus Data Distinction

The config/ folder contains two files. They look almost identical, their names differ by one word, and they do entirely different jobs. This catches every new Shopify developer at some point, so we will be explicit.

config/settings_schema.json is the DEFINITION. It is written by the developer. It lists every theme-level setting the merchant can configure: brand colours, brand fonts, social icons, global button styles, logo, favicon. Each entry in the file is a settings group with a name and an array of settings, each setting with a type, an id, a label, and optional defaults. You edit this file when you want to add a new global theme setting. The first group in the file is special: it holds the theme_info metadata (theme name, version, author, author URL), and removing or renaming it breaks the theme editor.

config/settings_data.json is the VALUES. It is written by Shopify. When a merchant changes their primary brand colour in the theme editor, Shopify updates this file. When a merchant saves a new template section arrangement, Shopify updates this file. As a developer, you almost never hand-edit settings_data.json. The one exception is presets. If you want to ship multiple style variants of the same theme (a dark preset, a warm preset, a minimal preset), the presets key in settings_data.json is where those live, and you do edit it by hand, carefully.

The short version you can repeat on day one: schema is the definition, data is the values. Schema is yours, data is Shopify's. If you are unsure which file to touch, you almost certainly want schema.

Assets and the CDN Budget Nobody Teaches

assets/ is a flat folder of CSS, JavaScript, images, SVGs, and fonts. Everything in it is served from Shopify's CDN, referenced in Liquid with the asset_url filter like {{ 'theme.css' | asset_url }}. There are no subdirectories. The folder is flat by platform constraint.

What beginner guides skip entirely is that assets/ is a budget, not a dumping ground. Every file you add becomes part of the theme's CDN bundle, part of its size on upload, and, if the file is linked from the document head, part of every shopper's first paint. Shopify caps theme uploads at 100MB, but the practical ceiling for performance is much lower. We aim for a total assets/ footprint under 5MB on custom builds, with any single render-blocking CSS or JS file kept under 100KB minified and gzipped.

The discipline is simple. Before any file lands in assets/, ask whether it is actually used, whether it is render-blocking or deferred, and whether a smaller format would work. Large PNG hero images that should be AVIFs, icon sprite sheets that should be inline SVGs, vendor JavaScript bundles for features the store does not use, old fonts left behind when the brand changed. We find all four on almost every audit. Each one is dead weight the shopper's browser downloads on the critical path.

One more note on Liquid in assets. You will occasionally see files like theme.css.liquid or variables.js.liquid. These let you inject Liquid variables into CSS or JS. Shopify has deprecated this pattern for performance reasons, because Liquid in an asset file forces that file to be rendered per request rather than cached as a static file. Modern practice is to ship plain CSS and JS and inject any dynamic values as an inline <style> block in the section that needs them.

Locales, the Invisible Folder

locales/ holds the translation files. en.default.json is the source of truth. It contains every hard-coded string in the theme, grouped by section and purpose, like general.search.title or products.product.add_to_cart. You reference these in Liquid with the translation filter: {{ 'products.product.add_to_cart' | t }}. Doing this from day one, even on single-language stores, costs nothing and saves weeks later if the merchant ever expands to a second market.

The second file pattern to know is en.default.schema.json. This file translates the theme editor UI itself, so when a merchant opens a section's settings, the labels they see are in their language. If you add a new setting to a section schema and want it translatable, you add its label as a key in en.default.schema.json and reference it in the schema with a t: prefix, like "label": "t:sections.product.add_to_cart". Every additional language gets its own file: fr.json, de.json, ja.json, and so on.

The File We Touch First on Every Project

For a brand customisation project, it is config/settings_schema.json. We scan it to see what global knobs the theme already exposes and what we will need to add. On a performance audit, it is layout/theme.liquid followed by a walk through assets/ with the file sizes sorted descending. On a bug fix, it is whichever section the theme editor highlights, opened next to the browser's rendered DOM. On a new custom build, it is Dawn's latest release on GitHub, unzipped fresh, with Dawn's theme.liquid and sections/header-group.json open side by side as the reference.

The pattern is worth naming. Good Shopify developers do not read themes file by file. They jump to the file that serves the stage of the rendering chain that matches the problem. Customiser-facing issue, go to schema. Render issue, go to layout or section. Size issue, go to assets. Translation issue, go to locales. The folder tree stops being an obstacle and starts being a map.

When the Tree Stops Being a Map

Most new Shopify developers spend their first three months genuinely confused about which file does what, making changes in the wrong place, and breaking things for reasons they cannot trace. That is normal. It takes a real project under a deadline, with someone watching the work, for the folder structure to click.

If you are a founder whose developer needs to customise a premium theme without breaking the editor, or a junior developer who has read every tutorial but still cannot ship a feature without a senior pair, that is the gap WitsCode fills. We build custom Shopify themes against the Dawn baseline, and we run paid upskill coaching for in-house developers walking through their first real theme.

→ Talk to WitsCode about a custom Shopify theme build or a junior-dev coaching block.

Get weekly field notes.

Practical writing on shipping products, straight to your inbox. No spam.

Need help with this?

Shopify Development

We design and build web apps, MVPs, and SaaS products. Talk to us about what you are working on.

Talk to us

Want to discuss ecom for your business?

Start a project and we'll talk through where you are, what's working, and the highest-leverage moves for the next 90 days.