What AI-Written Shopify Customizations Actually Look Like 6 Months Later


What AI-Written Shopify Customizations Actually Look Like 6 Months Later

The issue with AI-generated Shopify code usually isn't that it fails at launch; in fact, it often works well enough to go live. The real trouble surfaces later, when that code becomes a confusing, risky mess to update, creating a hidden drag on the team managing the store.

I've seen this play out enough times that the pattern is predictable. A team uses AI to build a custom section or patch a script to move faster. At the time, that feels like a win. A few months later, the theme is slower, the editor is less flexible, and nobody's sure what's safe to touch — even though nothing technically broke.

That's where the real cost lives. Not a break — friction. Merchandising changes that take longer than they should. Edits that nobody wants to make because nobody's sure what breaks if they do. Performance issues with no obvious source. Here's what's actually behind that, and how to tell if your store is carrying it.


How Shopify's Theme Architecture Is Designed to Work

Shopify's modern theme architecture is built around a specific logic. Once you see it, the maintenance problems AI code creates become obvious.

In Online Store 2.0, Shopify uses JSON templates to define which sections appear on a page and how merchants configure them. That structure is what allows merchants to add, remove, and reorder sections directly in the theme editor without touching code. The markup and Liquid logic live inside individual sections. The template stays focused on structure. Shopify also sets hard limits here: up to 25 sections per JSON template, 50 blocks per section, and section IDs must be unique within the template.

Section schema is where a lot of AI-generated code runs into trouble. Shopify's section schema defines the settings and behavior that let a section appear and function correctly in the editor — each section can include only one schema tag containing valid JSON (Shopify Dev Docs, 2025). When that schema is incomplete, the editor experience breaks down.

What I find isn't one dramatic mistake. It's accumulated shortcuts. Logic scattered across templates instead of contained in sections. Schemas that are partial or missing entirely. Reusable blocks duplicated instead of organized cleanly (Shopify Dev Docs, 2025). The section works on day one. Six months later, it's why your merchandising team is filing a ticket to move a layout element.

The hardcoded ID problem comes up constantly. AI-generated Liquid snippets hardcode section IDs and block IDs instead of letting Shopify generate them dynamically. When that happens, those sections lock in place — you can't move them in the theme editor, full stop (Shopify Dev Docs, 2025). In my experience, it's the single most common thing I find in stores where AI tools have touched the theme.

Styling works the same way. Shopify's architecture specifies the use of dedicated CSS assets and stylesheet Liquid tags (Shopify Dev Docs, 2025). However, AI bypasses this by inlining style blocks directly within the HTML. It doesn't look like a problem at first. When I audit a theme that's been through this, styles are scattered across multiple files. Nobody knows who owns what.

Code Example: OS2.0 Section Schema — Proper vs. AI-Generated

Version A: Proper OS2.0 Section

Editor-flexible. Movable. Maintainable.

{% comment %}
  featured-collection.liquid
  - Dynamic section ID (Shopify-generated — editor can move this)
  - Presets defined (section appears in "Add section" menu)
  - Blocks use shopify_attributes (editor can add/remove/reorder blocks)
  - CSS loaded via {% stylesheet %} (no inline style pollution)
{% endcomment %}

<div class="featured-collection" id="featured-collection-{{ section.id }}">
  <h2 class="featured-collection__heading">
    {{ section.settings.heading | escape }}
  </h2>

  <div class="featured-collection__grid">
    {% for block in section.blocks %}
      {% case block.type %}
        {% when 'product_card' %}
          <div class="product-card" {{ block.shopify_attributes }}>
            <p>{{ block.settings.product_title | escape }}</p>
          </div>
      {% endcase %}
    {% endfor %}
  </div>
</div>

{% stylesheet %}
  .featured-collection {
    padding: 40px 0;
  }
  .featured-collection__heading {
    font-size: 1.5rem;
    margin-bottom: 24px;
  }
  .featured-collection__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
  }
{% endstylesheet %}

{% schema %}
{
  "name": "Featured Collection",
  "tag": "section",
  "class": "featured-collection-section",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Featured Products"
    }
  ],
  "blocks": [
    {
      "type": "product_card",
      "name": "Product Card",
      "settings": [
        {
          "type": "text",
          "id": "product_title",
          "label": "Product Title"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "Featured Collection",
      "blocks": [
        { "type": "product_card" },
        { "type": "product_card" },
        { "type": "product_card" }
      ]
    }
  ]
}
{% endschema %}

What makes this editor-flexible:

  • {{ section.id }} — Shopify generates the ID dynamically. The section can be added multiple times and moved freely in the editor.
  • {{ block.shopify_attributes }} — Gives the editor control over each block. Merchants can add, remove, and reorder blocks without touching code.
  • presets — Without this, the section never appears in the "Add section" menu. The editor can't surface it.
  • {% stylesheet %} — CSS compiles into a dedicated asset. No style ownership problems when the theme gets updated.

Version B: AI-Generated Section

Works on day one. Breaks down over time.

{% comment %}
  featured-collection.liquid (AI-generated)
  - Hardcoded section ID — editor can't move this section
  - No presets — section doesn't appear in "Add section" menu
  - No shopify_attributes on blocks — editor loses block-level control
  - Inline <style> block — styles scattered, no clear ownership
{% endcomment %}

<style>
  .featured-collection {
    padding: 40px 0;
  }
  .featured-collection__heading {
    font-size: 1.5rem;
    margin-bottom: 24px;
  }
  .featured-collection__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
  }
</style>

<div class="featured-collection" id="featured-collection-main">
  <h2 class="featured-collection__heading">
    {{ section.settings.heading | escape }}
  </h2>

  <div class="featured-collection__grid">
    {% for block in section.blocks %}
      {% case block.type %}
        {% when 'product_card' %}
          <div class="product-card">
            <p>{{ block.settings.product_title | escape }}</p>
          </div>
      {% endcase %}
    {% endfor %}
  </div>
</div>

{% schema %}
{
  "name": "Featured Collection",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Featured Products"
    }
  ],
  "blocks": [
    {
      "type": "product_card",
      "name": "Product Card",
      "settings": [
        {
          "type": "text",
          "id": "product_title",
          "label": "Product Title"
        }
      ]
    }
  ]
}
{% endschema %}

What breaks down over time:

  • id="featured-collection-main" — Hardcoded. If this section is added twice, both instances share the same ID. The editor can't distinguish them and the section locks in place.
  • No presets — The section works if added manually to the JSON template, but merchants can never add it themselves through the editor. Six months later, nobody knows how it got there or whether it's safe to remove.
  • No {{ block.shopify_attributes }} — The editor renders the blocks but has no handle on them. Merchants can't reorder or select individual blocks in the editor UI.
  • Inline <style> — Every page that loads this section loads these styles inline. If the section is added twice, the styles load twice. When a developer scans the codebase for where .featured-collection is defined, they'll find it in the HTML, not a CSS file. Ownership is unclear.

The JavaScript Issues That Build Quietly

If the Liquid architecture affects your team's workflow, the JavaScript side hits your customers directly.

Google defines Total Blocking Time (TBT) as the total time between First Contentful Paint and Time to Interactive during which tasks longer than 50ms block the main thread—their threshold for a good experience: TBT under 200ms (web.dev, 2020). Largest Contentful Paint (the time for your main content to render) needs to come in under 2.5 seconds. Both metrics affect search rankings (web.dev, 2020).

AI writes JavaScript to make the feature work—not to minimize duplication or reduce main-thread load. What lands in the theme typically contains undocumented globals, inline scripts, and duplicated event listeners (web.dev, 2020). The impact doesn't hit all at once. A script here, a repeated dependency in the next revision, another listener added on top of that. None of it looks like a problem on its own. Stack enough of them, and TBT goes past 200ms, and six months from now, someone is spending a day tracing what's blocking the main thread (HTTP Archive Web Almanac, 2024).


What the Research Shows

The performance and maintenance debt caused by AI-generated code isn't anecdotal anymore. There's enough published research now to treat it as a documented pattern.

GitClear's large-scale analysis found that AI-assisted development increased code duplication and reduced refactoring, favoring quick patches over clean architecture (GitClear, 2023). Several academic and preprint studies report similar trends — higher code-smell density, worse cyclomatic complexity, and degraded maintainability index in AI-generated codebases compared to manually written ones, especially when snippets went straight to production without review. The most robust large-scale data point so far is GitClear's analysis. They found the same failure modes I see in Shopify themes: hardcoded patterns, structural inconsistency, and code that optimizes for shipping over longevity. Different context, same pattern.

None of this means store teams should avoid AI tools. It means the speed advantage at creation time and the maintainability cost over time are two separate things. The tradeoff is worth evaluating before it compounds.


What It Costs a Store Team 6 Months In

The cost doesn't announce itself. It shows up as everything taking slightly longer than it should.

Developer time. When custom code is inconsistent, duplicated, or lightly structured, even small updates require extra investigation before anyone feels comfortable making a change. What should be a short improvement becomes an audit, a regression check, and a round of cautious testing.

Storefront responsiveness. Extra JavaScript blocks the main thread. On mobile, TBT over 200ms is something users feel: the site seems sticky, unresponsive (web.dev, 2020). That's not abstract. It affects whether people complete a purchase.

Flexibility loss. When teams add sections, styles, and scripts in ways that don't align with Shopify's architecture, they become reluctant to remove or revise them. That hesitation is understandable, but it leaves unnecessary code running on every page load longer than anyone intended.


How to Check Your Theme

You don't need a full rebuild to get a read on whether this is happening. A few practical checks will tell you a lot.

1. Test your theme editor flexibility. Open your Shopify theme editor and try adding, removing, and reordering your custom sections. If certain sections feel rigid or behave differently from native ones, that's worth investigating. Shopify built JSON templates to support that editorial flexibility. If you can't move them, the cause is almost always hardcoded IDs or a missing schema underneath.

2. Check your Core Web Vitals. Pull up Google PageSpeed Insights and look at your real-world mobile data. LCP over 2.5 seconds or TBT over 200ms are worth tracing back to their source (web.dev, 2020). If those numbers worsened after custom theme work, JavaScript execution is the first place to look.

3. Test the store on mobile as a customer would. Tap menus, product variants, and add-to-cart controls before the page feels fully settled. That delay between tap and response is the main thread doing too much work during load (web.dev, 2020).


Conclusion

AI tools write code that works on day one. That's the easy part. What they don't do is write code that's easy to maintain, safe to modify, or built to last in a platform that keeps evolving. The architecture debt is quiet — until it isn't.

If you recognize these patterns: a theme editor that won't cooperate, TBT in the red, or a site that feels slower than it used to, an audit will surface exactly what was added and what's safe to remove.

Reach out if you'd like to take a look.

Want to know what your app stack is actually costing?

The Bloat Score Calculator takes 60 seconds. Enter your app count, monthly spend, and performance score — I'll tell you what to look at first.

Check My Bloat Score →