How We Used Gatsby.js to Build a Blazing Fast E-Commerce Site

Mae Capozzi
Nov 6, 2018 · 7 min read

Flamingo has landed! Harry’s, Flamingo’s parent company, serves over one million female customers. We believe that women deserve high-quality, reasonably priced, and simple body care products too.

As an engineering team, we are committed to providing women with a body care experience tailored to their specific needs. It’s important to us that our customers enjoy their interactions with us not only while they’re in the shower, but also when they shop for their blades, wax kits, or razor handles online too.

To simplify shopping for razors we built a performant, visually-appealing, and secure site. Our architecture performs well across browsers and devices, emphasizes developer ergonomics and modern tools, and lets us continuously deploy with confidence. We think can be a model for how to architect other e-commerce sites.

As excited as we are about what we’ve built, we try to stay realistic. We figured that we might be the only ones this engaged. To our surprise, we found out that other people actually did want to know how we built our site!

So here we go! These are the tools we used to build, why it works as well as it does, and how you can build similar applications to provide your users with performant, accessible experiences.

Static Sites vs. Web Servers

A little later, web servers arrived that could produce HTML dynamically. The typical flow looked like this: a user makes a request that may or may not be shielded by a CDN. That request hits the web server which interacts with a database or APIs. Based on the data that the database or API returns, the web server builds HTML pages and serves them to the browser.

Historically, static sites came with less security risks and prevented the application from spending time per request generating each page, making them more performant.

On the flip side, static sites made it difficult to share code between files. Additionally, a developer usually needed to update content on a static site since it was written into the HTML. For both of these reasons, large static sites could become difficult and time-consuming to maintain compared to a web server.

Unlike static sites, web servers could make real-time decisions about what content to show or hide to a user, providing more sophisticated personalization with less effort. But, building a web page dynamically every time a user visits a page takes a lot of time.

In recent years static site generators like Gatsby.js, Next.js, and Nuxt.js have made it much easier to walk a middle-ground between the static websites of the early web and dynamic web servers. It’s now possible to reap the performance and security benefits of a static site, while also having the ability to share code easily and fetch content from a CMS.

How Did We Do It?


Because Gatsby is a static site generator, we get to write code in React.js instead of writing HTML, CSS, and JS. Gatsby docs describe this process well; during the build process, Gatsby performs an “optimized production build” that generates “static HTML and per-route JavaScript code bundles.”

A Gatsby plugin called gatsby-source-contentful makes it straightforward to pull content and assets from Contentful into Gatsby. We query for that content using GraphQL.

We deploy and host our static files in S3, and serve a cached version of those files from Fastly, further reducing latency and thereby improving user experience.


Circle CI

Amazon S3


Our Hosting Architecture

A gorgeous diagram by yours truly

Imagine that we have a user in New York. That user makes a request to Once the DNS record is returned, we make a request to Fastly. Because there’s a Fastly node in New York, the request will (in most cases) go there.

We ask the Fastly node if it has cached the most current version of the site. If the Fastly node has the current version cached, it will return it to the user. That process eliminates the need for the request chain to continue and reduces latency. If the Fastly node does not have a current version of the site cached, it will make a request and ask the Fastly shield node whether it has the current version cached.

If the Fastly shield node has the current version cached, it will return that to the user, updating the node in the user’s region on the way. If it doesn’t have a cached version, it has to ask the S3 bucket.

After a new deploy, the first user in a region experiences the most latency. Their request will go all of the way to the S3 bucket, since none of the Fastly nodes have a cached current version of the site. Once that initial request goes through, all of the other users in that area can access the site from the closest Fastly node, reducing latency for them. Also, the first user will access a cached version of the site from then on, until we deploy new version of the site.

We work hard to deliver existing content to our users as quickly as possible, but what about new content? The second major component to our architecture allows us to deploy quickly and easily multiple times a day.

Deployment Flow

Ah, the joys of architecture diagrams

The process starts when someone triggers a build. To trigger a build, someone either pushes their code to Github or publishes a change to our CMS.

Circle CI Steps

  1. It runs Jest and checks to see if the Jest tests pass
  2. It runs Flow and makes sure all of our type-checking passes
  3. It runs the build and confirms the build passes
  4. It pushes changes to a branch
  5. It runs the Cypress tests
  6. (Optional Step) If we’re on master and all of the tests pass, Circle CI will rebuild the site with the production ENV variables.

If any of these steps fails, Circle CI will fail the build and the process will stop.

Once the build is green (on staging or master), Circle CI pushes the static files generated by Gatsby to S3, and the process described in the Hosting Architecture section begins.

The Whole System

The whole shebang!
  1. A developer or product manager pushes to Github or publishes to our CMS
  2. Circle CI triggers a build
  3. Gatsby builds the site
  4. Gatsby fetches data from our CMS.
  5. Gatsby passes data to GraphQL
  6. GraphQL passes data back to Gatsby
  7. Gatsby builds the static pages
  8. Circle CI pushes the static pages to S3
  9. Fastly fetches and serves the static site
  10. A user accesses

We sought to build a highly-performant e-commerce site, and believe we achieved just that. We love working on this application, and hope that you will consider using it as a model when you build your next e-commerce site.

We love working with people who are curious about software and how things work, who work to understand technical problems deeply, and who stay current. If you’re interested in working with this type of architecture, check out our careers page!

Harry's Engineering

The engineering blog of Harry's

Thanks to Brian Cobb, Andy O'Neill, Steven Natera, and Pablo Borges

Mae Capozzi

Written by

Senior software engineer @harrys. Web dev, music, literature. Whiskey fan. Opinions are my own. ~

Harry's Engineering

The engineering blog of Harry's

More From Medium

More on Software Development from Harry's Engineering

More on Software Development from Harry's Engineering

Planning Harry’s 2019 Hackathon


Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade