Skip to content

Next.js Caching Strategies ​

This guide details how the Bagisto Headless storefront leverages Next.js caching mechanisms to deliver high performance and scalability.

Overview ​

The storefront uses the Next.js App Router, which provides a sophisticated, multi-layered caching system. In Bagisto Headless, we primarily focus on three types: Request Memoization, Data Cache, and Full Route Cache.

1. Request Memoization ​

Next.js automatically dedupes fetch requests with the same URL and options. This allows us to call the same GraphQL query in multiple components (e.g., in a Layout and a Page) without incurring multiple network requests to the Bagisto backend.

  • Scope: Lasts for the lifetime of a single server request.
  • Benefit: Simplifies the component tree by allowing data-heavy components to fetch their own requirements safely.

2. Data Cache (Server Side) ​

We store the results of expensive GraphQL queries in the Data Cache to persist data across multiple user requests and deployments.

Implementation: We use unstable_cache from next/cache inside our graphqlRequest utility to manually cache results from the Bagisto API.

File: src/lib/graphql-fetch.ts

typescript
const cachedQuery = unstable_cache(
  async () => {
    // Fetch logic via Apollo Client
    return result.data;
  },
  [cacheKey], // Unique key based on query + variables
  {
    tags: options?.tags, // Cache tags for invalidation
    revalidate: getRevalidateTime(options?.life), // TTL
  }
);

Cache Lifetime Presets ​

The system supports several presets for revalidation:

  • seconds: 10s (Ideal for volatile data)
  • minutes: 60s
  • hours: 3600s (Default for most products)
  • days: 86400s (Ideal for static themes/categories)

3. Full Route Cache (SSG & ISR) ​

Next.js automatically caches the rendered HTML and data for static routes at build time. For e-commerce, we use Incremental Static Regeneration (ISR) to keep these static pages fresh without a full rebuild.

  • Product Pages: Generated statically with a revalidation period (e.g., 1 hour).
  • Category Pages: Cached at the route level to ensure near-instant TTFB.

Example from Product Page:

typescript
export const dynamic = 'force-static';
// Page is cached as a static route

4. Cache Invalidation (On-Demand) ​

To ensure the storefront reflects updates made in the Bagisto Admin (e.g., price changes or stock updates), we use Tag-based Invalidation.

By assigning tags like products or theme to our cached requests, we can purge specific chunks of the cache programmatically when the backend notifies the frontend of a change.

5. Client-Side Router Cache ​

The Next.js App Router has an in-memory client-side cache that stores the RSC (React Server Component) payload of previously visited routes. Combined with our custom LRU Cache, this ensures that navigating back to a product is instantaneous.

Best Practices ​

  • Explicit Revalidation: Always define a sensible life period for your GraphQL requests.
  • Granular Tags: Use specific tags like product-[id] for data that changes frequently, and generic tags like catalog for broad updates.
  • Prefer Static: Default to static rendering (force-static) for product and category pages to maximize CDN efficiency.

Next Steps ​

Released under the MIT License.