Watch Webinar: Figma - Design to Code in 80% Less Time

Announcing Visual Copilot - Figma to production in half the time logo
Talk to Us
Talk to Us










Visual CMS

Drag-and-drop visual editor and headless CMS for any tech stack

Theme Studio for Shopify

Build and optimize your Shopify-hosted storefront, no coding required



Get StartedLogin

‹ Back to blog

Learnings from migrating ShopStyle to Jamstack (2015 to present)

By Steve Sewell

Ecommerce websites need to be fast. But with so many technology choices out there, how do you know which is right for you? Read below to find our learnings, problems, and solutions of migrating ecommerce sites to a headless commerce architecture.

In 2014, we had an interesting predicament at ShopStyle. We had a massive monolithic codebase powering our entire tech stack - the user facing website, APIs, data ingestion, search... the list goes on. The tech was getting dated and difficult to work with, the site was slow and overly coupled, and releases were a hectic combo of praying, cursing, and tended to take forever. We wanted to improve the situation, but did not know exactly what to do next.

Tip: We suggest reading this updated article about Jamstack CMS.

When we first discovered AngularJS (then just called Angular) it was love at first sight. Simple, declarative templates with magical state powers. The code example below shows that Angular was new and unique, clearly ahead of everything else at the time.

After lots of research and testing, we decided to migrate ShopStyle's frontend to Angular.

Some key goals were:

  • Development efficiency. Need to be able to produce new code fast
  • UX. Users need to have a good experience on our site
  • Performance. Pages need to load fast
  • SEO. Critical to our traffic at the time, Google must like our site

Next we did what every excited developer does with shiny new toys, we started building! We got the boilerplate setup, started filling in the content, all was smooth, at first.

Then came finding all the challenges of adopting so early, with the rest of the ecosystem not necessarily yet evolved to support this move. *cue the sad violin music now*

The first challenge was APIs. We need content to load fast, and a standard REST-ful API wasn't going to cut it, as we were making many requests per page for the variety of content needed.

Our solution was to make new "page" APIs that aggregated all content needed for a page in one request, served from edge cache, and filtered down to just the properties the site needed.

This approach was odd and rigid, but it was good enough and worked for us at the time.

Solution: GraphQL

If we were doing the same thing over again today, we would have an even better and more flexible tool at our disposal: GraphQL. GraphQL is built exactly for this the use case of gathering bits of data from lots of different sources and packaging them up nicely for your project to consume.


Our next learning was that while Google at the time began saying, "we crawl Javascript rendered content", our experiments and data suggested otherwise. While they did seem to crawl some Javascript content, they clearly were missing most of it. ShopStyle has millions of web pages and Google's Javascript enabled bot was simply not crawling fast enough.

Solution: pre-rendering

We needed a way to render content server side using Angular, and to be able to do it fast. No off the shelf solution existed at the time, so to solve this we created a framework called Compylr that transpiled browser-only Angular templates to Handlebars - which can render on the server, very fast.

In order to support this, we did something that was discouraged at the time - we made one large state tree, that could easily be constructed on the client or the server, to pass to the Angular or Handlebars template. Ironically, this has become the best practice as of recently with frameworks like Redux becoming the go-to choice for single global tree state management.

<a ng-repeat="product in products" href="products/{{}}">
  <img src="{{user.image}}" ng-show="foo && bar">


  <div ng-include="'path/to/partial'">

{{#forEach 'foo' in bar}}
  <a ng-repeat="foo in bar" href="products/{{}}" ng-href="products/&#123;&#123;;&#125;">
    <img src="{{user.image}}" ng-show="foo" {{hbsShow "foo && bar"}} ng-attr-src="&#123;&#123;user.image&#125;&#125;">

    <span ng-bind="foo">{{foo}}</span>

    <div ng-include="'path/to/partial'">
      {{> path/to/partial}}

Today, there are even more options. In particular, we recommend Gatsby.

After solving those challenges, we built and launched the site. Great!

But then what came next? The business requests! Marketing would request new custom pages, copy updates, A/B tests, and personalization. Product would request new feature flags and more tests, and site managers needed content translated for many locales. Ooof!

To solve for this, we built a rough internal headless CMS. It used data models to allow some level of control for parts of the site. It wasn't amazing, but it was good enough.

Solution: see below

This was the one that really bit us, as it was a major paint-point as we scaled our web app. AngularJS wasn't really built to handle the complicated interfaces that a large-scale web app would need.

Client-side interactions started to feel slow, especially on mobile devices.

Solution: modern frameworks, in ShopStyle's case - Angular 2

Fortunately, we weren't the only ones to notice this problem, and the Angular team was already working hard to solve these problems.

Credit: Netlify

The appeal of the "new stack" - which has many names, such as "Jamstack," "Headless," "Progressive Web Apps" and more - started gaining global attention and progress.

More frameworks were coming out and taking on the challenges of making this new technology blazing fast, and finally overtaking the prior world of PHP+jQuery

React, Vue, Next.js, Nuxt.js Gatsby, Svelte, Angular, etc. began paving the way on the frontend. GraphQL adoption grew rapidly on the backend, and on the infrastructure side content delivery and compute at the edge really started taking off.

Combining these techniques we were able to make ShopStyle blazing fast. We were even called out on stage at Google Next and on Twitter by the core Angular team for our speed:

After what felt like a herculean effort to modernize our tech stack and optimize the s*** out of it, there was still a major remaining problem: content management

Our data-model based internal CMS was no longer cutting it. We even tried some up-and-coming headless CMSs only to find the same problem over and over again: there was still a never ending dependency on developers, and the requests didn't stop coming in:

"We need a new layout on our homepage for black Friday!" "We need to add a signup form on this new landing page!" "We need to show a different hero based on a visitor's shopping history!" "We need A/B tests on our new campaign!"

Ugh. We didn't have the staff, or the time, and we really did not want to be the ones blocking these important business updates. On top of that, we didn't want content to live in our code either.

What we needed was a site builder like Wix/Squarespace/etc. but that could work within our custom tech stack so that we could use our code components, leverage our existing tracking, SEO logic, performance optimizations, design library, etc. And we needed to be able to manage all of this content outside of our code.

So, I left ShopStyle in 2017 to make the first version of Builder. A headless, API-driven, visually editable CMS.

After seeing the benefits of this approach, combined with features that truly enabled non-developers to create, measure, optimize, repeat, without needing developers involved, but completely customizable and controlled by developers, it became obvious it was a no brainer.

We got ShopStyle as our first enterprise customer and quickly saw that many other commerce businesses, like Everlane, Vistaprint, Atoms, Afterpay, and more, had the same problem that Builder solved.

Maintaining performance and control, and delivering powerful features like drag and drop editing, landing page building, A/B testing and segmentation, was a game changer for these businesses migrating to the new stack.

The new world of development solves many problems of the old world, and new tools are cropping up every day to move our technology ecosystem forward to be faster, more scalable, and more optimized in every way.

The key problems and solutions we found were

If you are planning to go Jamstack, and just generally want to improve your existing site's performance, try out our Next.js + Shopify + Builder starter or our Gatsby + Builder starter.


Hand written text that says "A drag and drop headless CMS?"

Introducing Visual Copilot:

A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

Like our content?

Join Our Newsletter

Continue Reading
Web Development12 MIN
Figma to Angular: Convert Designs to Clean Angular Code in a Click
WRITTEN BYVishwas Gopinath
May 16, 2024
Web Development18 MIN
Getting Started with Mitosis: Creating a Cross-Framework Design System
WRITTEN BYVishwas Gopinath
May 7, 2024
Company News3 MIN closes $20 million in funding led by M12, Microsoft’s Venture Fund
WRITTEN BYSteve Sewell
April 24, 2024