Vue Storefront 2 useProductList composable performance with large catalogs without caching
0 reputation · 28 Sept 2026, 20:48 UTC
0 reputation · 28 Sept 2026, 20:48 UTC
Vue Storefront 2's useProductList composable renders product listings via GraphQL API middleware. The default caching provided by the @vue-storefront/nuxt module is documented for SSR, but cache invalidation behavior for frequently changing catalog data is not clearly specified.
State management uses Pinia with @vue-storefront/composition, which can introduce hydration considerations in SSR when cache layers are applied to large datasets. The interaction between GraphQL query complexity, Nuxt SSR rendering, and the framework's caching defaults creates uncertainty for catalogs exceeding several thousand products.
What measurement approach distinguishes GraphQL response time from Nuxt SSR render time for useProductList? Which cache scope is appropriate for product list data under SSR, and how is invalidation intended to be triggered for updates?
34775 reputation · 29 Sept 2026, 02:12 UTC
To isolate the GraphQL request latency from the Nuxt SSR rendering overhead of useProductList, measure the two phases separately on the server:
performance.now() (or Date.now()) before and after the awaited async data resolves.render:route hook (or nuxtHooks.render:before → nuxtHooks.render:after) for the same request.Subtracting the GraphQL interval from the total request time gives the pure rendering cost.
// inside a Nuxt server middleware or plugin
import { performance } from 'perf_hooks';
export default defineNuxtPlugin(({ nuxtApp }) => {
nuxtApp.hook('render:route', async (context) => {
const startRender = performance.now();
// let the page render normally
await nuxtApp.callHook('render:route', context);
const endRender = performance.now();
console.time('ssr-render');
console.timeEnd('ssr-render', endRender - startRender);
});
// Example usage in a page or component
const startGraphQL = performance.now();
const { data, pending, error } = await useProductList();
const endGraphQL = performance.now();
console.time('graphql-request');
console.timeEnd('graphql-request', endGraphQL - startGraphQL);
});
For a catalog that is shared across users and changes infrequently, a global (route‑agnostic) server‑side cache is appropriate. The cache should:
product-list) so all SSR requests hit the same entry.maxAge (e.g., 60 seconds) to allow timely updates while avoiding per‑request duplication.This approach prevents the per‑request cache from causing repeated GraphQL calls under high traffic while keeping hydration consistent.
The @vue-storefront/nuxt module invalidates cached useAsyncData results via a tag‑based mechanism:
.invalidate() method (or pass an invalidateOn array containing the relevant tags) when product data changes.$cache.removeTag('product-list').If your product list includes user‑specific filters (e.g., price range, locale), the cache key must incorporate those values; otherwise, the global cache could serve stale or incorrect data. Confirm whether any such filters are applied before finalizing the cache scope.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.