← All Insights
🧡
Case StudyShopifySymbAIotic Shiftβ„’

Frankenstein's Theme

Stitching React into Shopify's Liquid β€” and why brownfield is harder than greenfield

Yes, it's a Frankenstein reference. The monster that actually works. "Theme" = Shopify theme. "Stitching" = Nicole's literal business. You'll get it.

February 23, 2026 Β· 12 min read

"Building new is fun. Renovating is harder, messier, and way more relatable."

Last month I wrote about building a production SaaS in a weekend. Clean room. Blank canvas. Choose your tools. That was Scat Pack CLT β€” the greenfield origin story.

This is the sequel. And like most sequels, it's darker, messier, and way more complicated.

Because this time I walked into someone else's house.

The House That Shopify Built

Stitchwichs Custom Apparel & More. Charlotte, NC. My sister Nicole's business. Black woman-owned, sole proprietor, made-to-order custom apparel. Sigma Gamma Rho licensed vendor. Greek letter organizations, family milestones, community celebrations.

Her custom order page was turned off. Intentionally.

Not broken. Not forgotten. Nicole deliberately disabled it because Shopify's native forms couldn't handle what her business actually needed. Image reference uploads for custom designs. Greek letter selection with 3-layer applique color styling. Size grids for 50-person line jacket orders. Per-area customization β€” front, back, left sleeve, right sleeve, pocket.

She chose a dead link over a bad experience. That's a business owner who knows her craft.

An existing Shopify store with 224 products, 18 collections, 15 installed apps, real customers, and a live business that can't go down. You can't choose the stack. You can't redesign the schema. You have to work within Shopify's constraints β€” and Shopify has a LOT of constraints.

The App Tax

Meanwhile, the app bloat. 15 apps installed. ~$75-100/month in fees. Each one solves a narrow problem. Each adds JavaScript to the page. Each is another monthly line item eating margins on $25 custom t-shirts.

AppMonthlyThe Problem
Ymq Product Options$12.90Shopify can do size upcharges natively
Happy Birthday Marketing~$20Shopify Flow + a metafield does this for free
Draftable$7Shopify GraphQL API does this natively
BOGOS.io Free Gift~$15-30Requires Plus plan to replace β€” BLOCKED
Yotpo Reviews~$30Can migrate to metafields + Google reviews
Filemonk$10Actually needed β€” no native replacement

Oh, and one more constraint: Shopify Basic plan. Not Plus. That means no checkout extensions, no custom Shopify Functions, no Checkout UI Extensions. Half the "recommended" solutions don't work.

The Heist

Shopify doesn't have a staging environment. You can't run a dev server. You can't hot-reload Liquid templates. The iteration cycle for building directly in Shopify is brutal.

So the approach: build the entire custom order system in React (fast iteration, modern tooling, component reuse), then create a build pipeline that converts it into standalone JavaScript bundles that embed inside Shopify Liquid templates.

Build custom cabinets in the workshop. Install them in the existing kitchen. The kitchen doesn't know they were built with power tools.

Three Layers. One Monster.

Layer 1: Next.js Preview Site

The design workshop. Full React app with Tailwind CSS. 24 pages, 41 components, 21,744 lines of TypeScript. Deployed to Vercel for rapid iteration and client review.

Layer 2: Vite Build Pipeline

The conversion layer. Takes the React code and builds self-contained IIFE bundles. Four "shims" translate Next.js dependencies into vanilla browser JavaScript.

Layer 3: Shopify Theme

The installation. 12 custom Liquid sections, 7 JSON templates, 3 CSS overrides. The React bundles mount to DOM elements created by Liquid. Shopify serves them. Customers see a seamless experience.

The Stitches (Making React Think It's Still in Next.js)

Next.js has opinions. It wants its own router, its own image optimizer, its own server. Shopify has opinions too. It wants Liquid. It wants its CDN. It wants to be the only thing on the page.

Four shims make React think it's still in Next.js while actually running inside Shopify:

Next.js ModuleShimWhat It Does
next/linkHash-based <a> tagsConverts client-side nav to #/order/tops hash routing
next/imageStandard <img> + CDNChecks Shopify CDN URLs injected by Liquid, falls back to Vercel
next/navigationuseRouter hooksHash-change listeners replace Next.js router
'use client'Stripped entirelyVite plugin removes all directives β€” everything is client-side anyway

The result: 21,744 lines of React that Shopify doesn't even know is React.

What the Monster Can Do

Nicole's custom order page went from "turned off" to the most sophisticated ordering experience on any Shopify Basic store:

β†’
Category hub β€” 3 sections β€” Custom Apparel, Sigma Gamma Rho Licensed, Other Greek Organizations
β†’
4-step order flow β€” Product Details β†’ Sizing β†’ Design Details β†’ Review & Submit
β†’
25+ product styles β€” 6 top styles, 5 hat styles, 5 jacket styles, 5 Greek items, and more
β†’
Per-area customization β€” Front, Back, Left Sleeve, Right Sleeve, Pocket β€” each with technique selection
β†’
Greek letter picker β€” Org-specific presets with 1/2/3-layer applique color styling
β†’
Line jacket system β€” 3-50+ jackets for Greek crossing ceremonies, CSV member import, per-member sizing, $185-$315+ packages
β†’
Pricing engine β€” 5 bulk discount tiers (5% at 3+ through 25% at 50+) plus 75% rush surcharge
β†’
Auto-save β€” Orders persist to localStorage for 7 days β€” critical for mobile (58% of traffic)
β†’
Shopify Draft Order API β€” Submits real draft orders via GraphQL with customer matching and workflow tagging

Apps Replaced

AppWas PayingWhat We BuiltSaved
Ymq Product Options$12.90/moCustom Liquid snippet for variant pricing$155/yr
Birthday Marketing~$20/moShopify Flow + customer metafield~$240/yr
Draftable$7/moDraft Order API via GraphQL$84/yr
Custom Order Page$0 (OFF)Full React order system β€” 21,744 LOC$15K-40K/yr recovery

The Hard Parts

If you read my last post, you know the rule: you have to show what went wrong. Here's what almost broke this build.

shopify theme push --only deletes assets

Sounds harmless. The --only flag should push just the matching files. Instead, the "Cleaning" step deleted every matching asset before uploading. New uploads failed silently. Every jacket image on the preview theme β€” all 404s.

Fix: --nodelete flag on every push. Learned the expensive way.

The 62.5% Font-Size Trap

Shopify's Spotlight theme sets html { font-size: 62.5% } so their rem values resolve to nice round pixel numbers. Tailwind expects 1rem = 16px. The entire order system rendered at 62.5% correct size β€” buttons too small, text unreadable, spacing compressed.

Fix: One CSS line. Three hours to find. html:has(#sw-order-root) { font-size: 100% !important; }

Collection Images Aren't Theme Assets

Uploaded 25+ product images to theme/assets/ β€” those work fine. But collection banner images live in Shopify admin on the collection object. Can't push them via CLI. 10 of 18 collections had no image set.

Lesson: The theme worked perfectly. The data was just missing. Different problem, different solution.

The Image Resolution Chain

React components use paths like /images/category-tops.png. On Vercel, that resolves to the public directory. On Shopify, that path means nothing. Built a 4-step resolution chain: Liquid generates window.__SW_JACKET_IMAGES__ β†’ React shim checks it β†’ falls back to Vercel β†’ every new image requires the full pipeline.

Pain: Had to add images to the map three separate times as we discovered missing ones.

Two Different Image Arrays, One Page

The order page has PRODUCT_CATEGORIES in one file and OTHER_GREEK in another. Updated the wrong array with Greek org images. Nicole caught it. Different sections, different data sources β€” the code structure doesn't make that obvious when you're moving fast.

Lesson: Speed creates blind spots. Client QA catches what you miss.

The Numbers

21,744
Lines of Code
208
Custom Files
3.4x
Shift Multiplier
62%
Cost Savings
MetricTraditionalSymbAIoticβ„’
Hours284-31283-89
Duration14 weeks3 weeks
Cost$42,600-$46,800$16,600-$17,800

Annual Impact

$479
App savings (achieved)
$15K-$40K
Revenue recovery (custom orders back online)
$42K-$67K
First-year total value

Greenfield vs. Brownfield

Scat Pack proved the SymbAIotic Shiftβ„’ works from zero. Clean room. Choose your tools. Build fast.

Stitchwichs proved it works in the mess. Existing store. Existing customers. Platform constraints. App dependencies. A business owner who knew what she wanted but couldn't get it from the tools she had.

Scat Pack (Greenfield)

  • Choose any stack
  • Design from scratch
  • No legacy constraints
  • 24 hours to production

Stitchwichs (Brownfield)

  • Work within Shopify
  • Renovate, don't replace
  • 224 products, live customers
  • 3 weeks, 3 layers, zero downtime

Every business has a version of Nicole's problem. Not a blank canvas that needs painting β€” a house that needs renovating. Apps stacked on apps. Workarounds on workarounds. A feature that's been turned off because the platform couldn't deliver.

The SymbAIotic Shiftβ„’ isn't just for greenfield dreams. It's for the businesses that already exist, already have customers, and need to get better without burning everything down.

Why This One's Personal

Scat Pack was built with my son. This one was built for my sister.

Nicole's been stitching custom apparel for years. She knows every thread weight, every applique technique, every Greek organization's color scheme. What she didn't have was a platform that matched her craft.

The SymbAIotic Shiftβ„’ isn't about replacing people with technology. It's about building technology that matches the people who already know what they're doing.

What Would You Fix This Weekend?

Your Shopify store. Your SaaS idea. Your business running on spreadsheets and duct tape. Whatever it is β€” the tools exist now to build it right.

Greenfield or brownfield. We build both.

Let's Build β†’

For the Nerds: The Three-Layer Architecture

React β†’ Vite β†’ Liquid. The monster's anatomy.


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  LAYER 1: NEXT.JS PREVIEW SITE (Vercel)                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”               β”‚
β”‚  β”‚ 24 Pages β”‚ β”‚ 41 Comps β”‚ β”‚ 2 API    β”‚ β”‚ 2 React  β”‚               β”‚
β”‚  β”‚ + Routes β”‚ β”‚ + Shared β”‚ β”‚ Routes   β”‚ β”‚ Contexts β”‚               β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜               β”‚
β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β”‚                    21,744 lines TypeScript                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚  vite build (IIFE)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  LAYER 2: VITE BUILD PIPELINE                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚  β”‚ sw-order-bundleβ”‚ β”‚ sw-lj-bundle   β”‚ β”‚ sw-style.css   β”‚           β”‚
β”‚  β”‚ 446KB IIFE     β”‚ β”‚ 419KB IIFE     β”‚ β”‚ 43KB scoped    β”‚           β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β”‚          β”‚                  β”‚                   β”‚                    β”‚
β”‚  4 SHIMS: next/link β†’ hash | next/image β†’ CDN | 'use client' β†’ βˆ…   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚  theme push --nodelete
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  LAYER 3: SHOPIFY THEME (Spotlight + Custom)                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ 12 Custom   β”‚ β”‚ 2 React     β”‚ β”‚ 7 JSON      β”‚ β”‚ 3 CSS        β”‚  β”‚
β”‚  β”‚ sw-* Liquid β”‚ β”‚ Embed       β”‚ β”‚ Page         β”‚ β”‚ Override     β”‚  β”‚
β”‚  β”‚ Sections    β”‚ β”‚ Sections    β”‚ β”‚ Templates    β”‚ β”‚ Files        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  Mounts to: #sw-order-root + #sw-lj-root                            β”‚
β”‚  Image bridge: window.__SW_JACKET_IMAGES__ (Liquid β†’ React)         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

WHAT WAS BUILT

  • Order system: 6 categories, 25+ styles, 4-step flow
  • Line jacket system: Group orders 3-50+, CSV import
  • Greek letter picker: Org presets + color layers
  • Pricing engine: 5 bulk tiers + rush surcharge
  • Draft Order API: GraphQL β†’ Shopify admin
  • Theme reskin: 12 sections + brand CSS
  • App replacements: 3 paid apps β†’ custom code
  • Auto-save: localStorage persistence (7 days)

PRODUCT CATALOG

  • 224 products across 18 collections
  • Custom Tops (6 styles)
  • Custom Hats (5 styles)
  • Custom Jackets (5 styles)
  • Greek Items (5 types)
  • Events & Special Occasions
  • SGRho Licensed Line
  • Line Jacket Ceremony Packages
KL

Ken Leftwich

Founder & Chief SymbAIote, L7 Shift
Enabling the SymbAIotic Shiftβ„’

Share this article

Share on LinkedInShare on X