Shopify Liquid Comments: 3 Syntaxes That Survive Theme Editor

A developer messaged me at 11:47 PM on a Tuesday in February 2026. His Shopify Plus storefront was leaking internal margin notes to view-source. He had pasted them in <!-- … --> because that was what he typed in PHP for a decade. Forty stores down the contractor chain, the same HTML comment pattern had shipped on a B2B storefront with wholesale pricing context inside.

TL;DR: Liquid has three comment forms: {% comment %} … {% endcomment %} (block, stripped), {# … #} (inline, stripped), and HTML <!-- … --> (NOT stripped, ships to the browser). Use the Liquid forms for anything internal. The inline form is the modern shortcut. Add whitespace dashes ({%- comment -%}) when you need the gap removed too.

Why this matters for your store:

  • HTML comments expose business logic, internal pricing notes, deprecated code paths, and contractor handoff context to anyone who hits view-source.
  • Theme Check ships in every fresh shopify-cli install but does not flag HTML comments inside Liquid templates. The audit is on you.
  • A leaked margin note on a Shopify Plus B2B storefront triggered a competitor undercut on one client in March 2026. They held the loss to one purchase order only because the buyer flagged it back.

The three Liquid comment forms

Block comment

{# sections/product.liquid #}
{% comment %}
  Skip the trust-badge row on PDPs flagged as wholesale.
  Marie asked for this in Slack on 2026-03-14 after the
  contractor mistakenly enabled it on all SKUs.
{% endcomment %}
{% unless product.tags contains 'wholesale' %}
  {% render 'trust-badges' %}
{% endunless %}

The block form wraps multi-line notes, ticket references, and decision context that future-you needs in six months. Anything inside {% comment %} is parsed but never rendered. The block survives shopify theme check, ships clean, and never appears in view-source.

One subtlety: the parser still walks the comment block. If you paste an unbalanced {% if %} or {% for %} inside, Theme Check may flag the parent file. To safely disable a control-flow block, see the dedicated pattern at the end of this post.

Inline comment (the modern shortcut)

{# sections/product.liquid #}
{% if section.settings.show_compare_at and product.compare_at_price > product.price %}
  {# Compare-at only fires when settings AND data agree. The merchant
     forgets to unset compare_at after sales. We default to settings as
     the source of truth. #}
  <span class="compare-price">{{ product.compare_at_price | money }}</span>
{% endif %}

{# … #} is the inline form, available on every Shopify theme since the 2022 Liquid update. It strips the same way the block form strips, parses faster (no closing tag to match), and reads cleaner for short notes. Use it for one-line or short multi-line context that sits next to the code it describes.

The inline form is what I default to on new sections. It looks like Python’s # comment or PHP’s // comment, which means contractors from other stacks pick it up without rewriting their reflex.

HTML comments (the leak path)

{# sections/product.liquid #}
<!-- Wholesale margin: 42%. Retail margin: 18%. Set by Andrew 2025-11. -->
<div class="product__price">
  {{ product.price | money }}
</div>

<!-- … --> is not a Liquid form. The Liquid parser passes it through to the rendered HTML. The browser hides it from screen render but anyone hitting Ctrl+U sees it in plain text. So do crawlers. So does the Wayback Machine archive of your storefront from last Tuesday.

I have caught this antipattern on 4 themes I audited in 2025-2026, including one Shopify Plus B2B build where margin breakdowns sat in <!-- --> comments under every variant’s price. The contractor handoff doc had said “leave notes in comments.” The dev’s reflex from a non-Liquid stack did the rest.

For broader Liquid mechanics including the operator precedence trap that turns nested if blocks into surprise outputs, see my Shopify Liquid development guide and the operator precedence reference.

The whitespace dash that removes the gap too

{% comment %} strips the comment body but leaves the whitespace around the tags intact. Three blank lines in your source still ship as three blank lines in the rendered HTML.

{# Before whitespace dashes #}

{% comment %}
  Disabled this row in March 2026.
{% endcomment %}

<div class="next-row">…</div>

Rendered output:



<div class="next-row">…</div>

Two blank lines made it through. On a collection grid with 60 disabled comment blocks (an FDB pre-launch staging build in April 2026), this added 4KB of whitespace to the gzipped HTML response. Not enough to fail Core Web Vitals, but enough to wrinkle a clean view-source.

The dash form trims:

{# After whitespace dashes #}
{%- comment -%}
  Disabled this row in March 2026.
{%- endcomment -%}
<div class="next-row">…</div>

Rendered output:

<div class="next-row">…</div>

The leading {%- dash trims whitespace before the tag. The trailing -%} dash trims whitespace after. Use the dash form when the comment sits in a layout where whitespace matters (table rows, inline lists, dense markup). Skip the dashes when the comment sits inside a code block where line breaks are already irrelevant.

How to disable a control-flow block safely

The naive approach is to wrap a section in {% comment %}. The parser walks the wrapped content and may flag unclosed control flow:

{# Naive disable. Parser walks {% if %} inside the comment. #}
{% comment %}
  {% if product.available %}
    <button>Add to cart</button>
  {% endif %}
{% endcomment %}

The safer disable: wrap the parent control flow with a guard that evaluates false, leaving the underlying code intact for fast re-enable:

{% assign disable_until_april = true %}
{% unless disable_until_april %}
  {% if product.available %}
    <button>Add to cart</button>
  {% endif %}
{% endunless %}

This pattern survives Theme Check, makes the disable visible in code review (one named boolean, one PR), and re-enables with a single line change. For the broader pattern around {% unless %} and when to use it over {% if %}, see my reference on the Shopify Liquid unless tag.

How to verify your comments are not leaking

Three checks, three minutes.

  1. Grep for HTML comments. grep -rn '<!--' sections/ snippets/ templates/ layout/. Every hit is a candidate. Compare it to a known-safe list (head meta tags, schema markup) and rewrite anything outside that list to {# … #}.

  2. Curl your live PDP and grep the response. curl -s https://your-store.com/products/test-product | grep -n '<!--'. Anything that surfaces is in the rendered HTML and exposed to crawlers. Schema-org markers are safe; everything else is rewrite-bait.

  3. Audit the contractor handoff doc. If the doc says “leave notes in comments” without specifying Liquid syntax, the next dev will paste HTML by reflex. Update the doc to specify {# … #} and add the grep command to the contractor’s pre-deploy checklist.

The takeaway:

  • Use {# … #} for short inline comments and {% comment %} for multi-line blocks.
  • Never paste internal context in HTML <!-- --> comments. Liquid does not strip them.
  • Add {%- … -%} dashes when the surrounding whitespace also needs to go.
  • Disable control-flow blocks with a named boolean guard, not a wrapping comment block.
  • Grep your repo and curl your live PDPs every release for stray <!-- strings. The audit takes 3 minutes and catches the leak before a competitor does.

Frequently Asked Questions

What is the comment syntax in Shopify Liquid?

Shopify Liquid has three comment forms. The block comment `{% comment %} … {% endcomment %}` wraps a multi-line block and is stripped at render time. The inline form `{# … #}` is the modern shortcut, available in every theme since the 2022 Liquid update, and behaves identically. HTML comments `<!-- … -->` survive into the rendered page, exposing whatever you wrote to view-source. For any note containing internal context, prices, or business logic, use a Liquid form.

Are Liquid comments visible in view-source?

No, Liquid comments are stripped server-side before the HTML reaches the browser. `{% comment %}` and `{# %}` blocks never appear in view-source. HTML comments `<!-- … -->` are different: Shopify treats them as part of the response body, so anything inside them ships to the client. Audit your theme with `grep -rn '<!--' sections/ snippets/` to catch business notes accidentally written in HTML comment syntax.

Does Liquid have inline comments like JS or Python?

Yes. `{# this is an inline comment #}` works on a single line and is the modern Shopify Liquid syntax for short notes. It compiles to the same nothing the block form compiles to. Use the inline form for short context (one line, end-of-line note). Use the block form when the comment runs more than a sentence or wraps disabled code.

Can I comment out a section block in Liquid?

Yes, wrap the section block in `{% comment %} … {% endcomment %}`. The parser walks the block but skips rendering. One catch: if the disabled block contains an unclosed `{% if %}`, `{% for %}`, or `{% schema %}` tag, theme check still parses inside the comment and may flag the unclosed control flow. The safer pattern for disabling is to remove the file from the section index or rename it temporarily.

Why do my Liquid comments still show up in the rendered HTML?

Two causes. The first is that the comment is in HTML syntax (`<!-- -->`), which Shopify does not strip. The second is whitespace control: `{% comment %}` leaves the surrounding whitespace intact, so the blank lines around the comment can still appear in the output. To strip the whitespace too, use the dash form: `{%- comment -%}…{%- endcomment -%}`. The dashes trim leading and trailing whitespace on both tags.

Book Strategy Call