← Back to work
case study · Shopify public app

FlexSync

A public Shopify app that keeps a merchant's product catalog in continuous two-way sync with Google Sheets — export products, variants, and inventory into a spreadsheet, bulk-edit them where merchants already work, and push every change back to Shopify without the two systems ever drifting apart.

RoleSole engineer · WPPOOL
Timeline2023 — present
SurfaceLive on the Shopify App Store ↗
OwnershipArchitecture → backend → frontend → ship
4M+
requests / month
400+
merchants in production
60%
sync latency cut
1
engineer — solo-built
Laravel 12React 18TypeScriptMySQLRedisShopify GraphQL Admin APIBulk Operations APIGoogle Sheets APIApps Script
the problem

Merchants live in spreadsheets. Shopify doesn't.

Store operators run their catalog in Google Sheets — pricing rules, supplier stock feeds, seasonal bulk edits, VLOOKUPs against a wholesale list. But Shopify's admin is a one-record-at-a-time UI, and its CSV import/export is a lossy, fire-and-forget round trip: you export, edit offline, re-import, and pray nothing collided while you were away.

There was no dependable live bridge. Merchants wanted the spreadsheet to be a real working surface — edit a price in a cell and have Shopify reflect it; sell a unit on Shopify and have the sheet reflect it — with neither side silently overwriting the other. That's a distributed two-way sync problem hiding behind a friendly “just a spreadsheet” UX, and the hard parts are all the ones a merchant never sees.

what i built

One app, two directions, no drift.

FlexSync is a Laravel + React public app that installs on a store, connects a Google Sheet, and then keeps the two in agreement continuously. A merchant works entirely in the spreadsheet they already know; FlexSync owns the messy middle — rate limits, async bulk jobs, webhook fan-in, conflict resolution, and echo suppression so an update never bounces back and forth forever.

  • Shopify → Sheets. Full-catalog export of products, variants, inventory, and metafields into a structured sheet, then incremental updates as the store changes.
  • Sheets → Shopify. Edits in the spreadsheet — including live spreadsheet formulas for price and stock — resolve to values and push back to Shopify.
  • Formula sync. A merchant can write =cost*1.4 in a price cell; FlexSync evaluates it and writes the result to Shopify, so pricing logic lives where the merchant already keeps it.
  • Passive by default. Once connected, it just stays correct — no manual re-import, no “click to sync” ritual.
how it works

The engineering under the spreadsheet.

A serialized bulk-operation queue

Shopify's Admin API is cost-based and aggressively rate-limited, and bulk reads/writes run as asynchronous jobs you poll for completion. A naive “fire a mutation per row” design dies instantly at catalog scale. FlexSync routes every write through a serialized, per-shop queue on Laravel + Redis: work is batched into Bulk Operations, only one bulk job per store is ever in flight, and the queue backs off and resumes around Shopify's throttle instead of hammering into it.

Buffered, webhook-driven updates — 60% less latency

Store-side changes arrive as webhooks. Rather than process each one synchronously, FlexSync buffers bursts and coalesces them: ten edits to the same product in a few seconds collapse into one downstream sync instead of ten. That buffering is where the 60% sync-latency reduction came from — less redundant work on the hot path, fewer API calls spent, and a system that stays responsive during bulk store activity.

Drift and echo prevention

The core hazard in any two-way sync is the feedback loop: FlexSync writes to Shopify, Shopify fires a webhook, FlexSync reads it as a “new” change and writes it back — forever. I solved that with change-origin tracking and version stamping so the engine recognizes its own echoes and drops them, and applies a deterministic resolution rule when both sides move at once. The two systems converge instead of oscillating.

Scaling to 4M+ requests a month

At 400+ live stores, webhook plus user traffic crossed several million requests a month. The scaling work was unglamorous and effective: MySQL index optimization on the hot sync and lookup paths, keeping the queue serialized per shop so no single store could starve the rest, and pushing everything that didn't need to be synchronous off the request path. It holds that volume on modest infrastructure.

results

What shipped, and what it moved.

  • 400+ merchants running it in production against their live catalogs.
  • 4M+ requests a month handled — webhooks and user traffic — on a serialized queue.
  • 60% lower sync latency after moving to buffered, coalesced webhook processing.
  • Formula sync shipped — a feature merchants specifically asked for, because it let their pricing logic stay in the sheet.
  • 5★ App Store reviews that call out the support as much as the product.
“Super helpful app and passionate, supportive developers. They really spent time trying to solve an issue for me when they didn't have to! Thanks so much!”
lizfrydesign · 5★ review, Shopify App Store
the takeaway

Why this project is the one I lead with.

FlexSync is a distributed-systems problem — idempotency, rate limits, async job orchestration, conflict resolution, convergence — wearing a spreadsheet's clothes. I owned all of it: the architecture, the Laravel backend, the React frontend, the Shopify and Google integrations, and the operational reality of keeping 400+ stores correct every day. Solo, in production, on a narrow stack, under real constraints.

That's the signal I care about: not a feature list, but ownership and shipping under constraint — the same thing I'd bring to an early team.

Want the deeper walkthrough?

Happy to whiteboard the queue design, the webhook buffering, or the drift-prevention model.