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.jsSanity 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 CMS

      Sanity is used for storing information about our e-commerce products. The data from Sanity is fetched using GROQ – a query language, used for fetching data. Formidable built Groqd  – a schema-unaware, runtime and type-safe query builder for GROQ.
    • 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 from getServerSideProps 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 the Fastly-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’ slugs as part of our surrogate-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’s  slug about what data changes, and our API endpoint uses that slug to tell Fastly which cache data to invalidate (based on the surrogate-key set in the original response header).