Headless commerce · Publishing
Simon & Schuster
Rebuilt the storefront of one of the world's largest publishers as a headless application — two regional storefronts, a catalogue three orders of magnitude larger than a typical store, and a cutover on a site that never stopped transacting.
- Catalogue size
- 300,000+ products
- Regions
- 2 (US & UK)
The problem
A publisher's catalogue behaves nothing like a normal store. 300,000+ SKUs meant collection pages, search and sitemaps all fell off the edge of what templates and standard pagination handle gracefully. Two regions needed different pricing, availability and fulfilment while sharing one commercial backend. And because the existing site was already transacting, none of it could be replaced in a single cutover — the new storefront had to run alongside the old one and take over incrementally.
What I built
Moved the storefront to a headless Next.js application reading from the Shopify Storefront API, so rendering, caching and routing were no longer constrained by theme limits.
Reworked collection and search surfaces to page over cursors incrementally with cached boundaries, rather than assuming any query could be walked in a single request.
Used the Admin API for the operations the Storefront API deliberately does not expose — inventory reconciliation, metafield-driven merchandising, and bulk catalogue operations against a 300k-product dataset.
Kept the platform's own checkout via the Buy Button SDK rather than rebuilding it. Checkout is the one surface where a custom implementation costs far more than it earns.
Built region routing so the US and UK storefronts share components and content models but resolve separate catalogues, pricing and inventory at the edge.
Covered the paths that lose money when they break — add to cart, checkout hand-off, region switching — with Cypress end-to-end tests running in CI.
Architecture
The commerce platform stays the system of record. The Next.js application owns rendering, caching and the customer experience; checkout is deliberately handed back.
Client
Edge / Cache
Commerce APIs
Systems of record
What was hard
A catalogue that broke normal pagination
Cursor-based pagination is fine for 500 products and painful at 300,000. Collection and search surfaces were reworked to page over cursors incrementally with cached boundaries, rather than assuming any query could be walked in a single request.
Cache invalidation across 300,000 pages
Incremental regeneration is straightforward until a catalogue-wide price change means the invalidation fan-out is itself the expensive operation. Cache tags had to be granular enough to avoid rebuilding everything, and coarse enough that a single product update did not require tracking every page it appeared on.
Inventory drift between systems
With two regions and an external source of truth for stock, inventory silently diverged. I built a sync path over the Admin API with reconciliation, so drift was detected and corrected rather than surfacing as an oversell at checkout.
Debugging a checkout you do not own
Headless checkout failures are hard precisely because the failing surface is the platform's, not yours. I traced hand-off failures across the SDK boundary using pixel and network-level evidence to separate our bugs from platform behaviour — which is most of the work in getting a headless checkout stable.
Business impact
- Two regional storefronts shipped on a shared codebase, so a change ships once instead of twice.
- Catalogue operations that previously timed out at 300k products run reliably.
- Checkout hand-off failures became diagnosable, with pixel-level evidence rather than guesswork.
- Funnel instrumentation gave the merchandising team data they could act on.
Technologies
Working on something like this?
I'm open to senior Shopify and full stack roles. Tell me what you're building.