Learn more about the Formidable Ecommerce demo site
We don’t really sell bread. The goal of the project is to provide a realistic demonstration of running a highly performant and available e-commerce site with data sourced from Sanity’s headless CMS. The app is powered by Next.js, Sanity CMS, and Fastly.
Headless CMS-driven architecture.
The e-commerce data is stored in a headless CMS (powered by Sanity). The project uses Next.js (deployed on Vercel) to render the site, and Fastly is placed in front of Vercel to cache server-rendered webpages for speed and availability.
Sanity Studio
Sanity Studio is a web interface for Sanity’s headless CMS. It is used for creating and editing the data on the site. The models for Sanity are created in code and tracked in source control. Sanity Studio is integrated into the NextJS application and deployed alongside as a route.NextJS app
To show the CMS data to end-users we created a Next.js web app that server-renders some common e-commerce pages, including a landing page, a Product Listing Page (PLP) with sorting and filtering, and a Product Details Page (PDP). The Next.js app is deployed to Vercel via their git pipeline. In a real-world e-commerce app, we expect to experience some heavy loads on pages whose data doesn’t change much between visits, and therefore we can deploy caching strategies to reduce the load on our source server.
The caching story.
Fastly CDN and Caching
In order to enhance the speed of the app, we are utilizing Fastly’s CDN with a high cache-lifetime for server-rendered pages. We are using Fastly to both cache and host the subdomain used for this showcase app. The data flow involved in caching is illustrated below:
To cache our server-rendered pages at the Fastly layer, we use response headers to indicate what/how we want Fastly to cache our responses from the source server. We need to a couple key ingredients:Surrogate-Control
response header needs to be added to pages where caching is desired. Learn more.Surrogate-Key
response header needs to be added to enable appropriate cache invalidation. Learn more.
On the Next.js side we’ll need to include a few primary response headers to then control caching (in our case, we’re setting these headers fromgetServerSideProps
on server-rendered pages that we’d like to cache).surrogate-control
Fastly-specific header used to set the cache policies.surrogate-key
Fastly-specific header that allows purging by key. Note: this header is removed by Fastly before sending the response to the client. To see the value of this header, you must include theFastly-Debug
header in your request.cache-control
used to indicate to browsers and Vercel to not cache so that we can handle caching solely at the Fastly layer.
With these response headers implemented, Fastly will start caching our responses and give us a path to invalidate our cache when necessary. In our case, we use data items’
slug
s as part of oursurrogate-key
header to indicate what items’ data are used to render a page so that we can invalidate accordingly when any of those items’ data changes.Cache Invalidation and Purging
When CMS data changes, a Sanity webhook is triggered and makes a request to an API endpoint in our Next.js app. The endpoint does some validation on the request (to make sure it’s coming from a trusted Sanity webhook), and then makes a request to Fastly’s API to invalidate/purge our cache accordingly. The Sanity webhook payload contains information (in our case, an item’sslug
about what data changes, and our API endpoint uses thatslug
to tell Fastly which cache data to invalidate (based on thesurrogate-key
set in the original response header).