Storefront Production Optimization Tips
Rendering, caching, and query tips for production.
On this page
In this guide, you’ll find tips useful when optimizing a storefront for production.
Summary
When building a storefront, you want to ensure that it loads quickly and efficiently for your users. You can achieve this by implementing many optimizations, including:
- Implement appropriate rendering strategies.
- Use fetching libraries optimized for performance and caching like TanStack Query.
- Optimize queries to fetch only the necessary data.
- Implement optimistic UI updates for cart operations.
This guide explains how to implement these optimizations. You can follow it regardless of the frontend framework you use.
There are other important optimizations like lazy-loading images, code-splitting, and using CDNs. These optimizations depend on the frontend framework you use and your setup. This guide focuses on Aiminaabee-specific optimizations in your storefront.
Choose the Right Rendering Strategy
A rendering strategy defines how your frontend framework renders pages. The most common strategies are:
- Server-Side Rendering (SSR): Pages are rendered on the server for each request. Ideal for dynamic content that changes frequently.
- Static Site Generation (SSG): Pages are pre-rendered at build time. Best suited for content that doesn't change often.
- Incremental Static Regeneration (ISR): A hybrid approach where pages are pre-rendered at build time but can be updated at runtime. Perfect for content that changes occasionally.
- Client-Side Rendering (CSR): Pages are rendered in the browser using JavaScript. Optimal for highly interactive applications.
For your storefront, we recommend using different strategies for different pages:
| Page Type | Recommended Strategy |
|---|---|
| Homepage | SSG above the fold, CSR below the fold. For example, render the hero section at build time and load product recommendations client-side. |
| Product Listing Page (PLP) | SSR or ISR. Fetch products on the server with region_id. |
| Product Detail Page (PDP) | SSR or ISR for catalog fields. Pass region_id for prices; inventory can stay dynamic. |
| Cart and Checkout Pages | Server components + server actions. Persist cart ID and JWT in httpOnly cookies. |
| Blog or Content Pages (About Us, Privacy Policy, etc...) | SSG or ISR. |
| User Account Pages | SSR with _aiminaabee_jwt. |
On Next.js App Router, follow Build a Next.js Storefront: SDK calls in src/lib/data/*.ts, cache tags from _aiminaabee_cache_id, revalidate carts, customers, and fulfillment after mutations. TanStack Query below is optional for client islands, not a replacement for the server data layer.
Use TanStack Query
When fetching data from your Aiminaabee backend, consider using a fetching library optimized for performance and caching. There are many options available, but one of the most popular is TanStack Query.
TanStack Query is a powerful data-fetching library that provides features like caching, background updates, and optimistic updates.
By using TanStack Query, you can significantly improve your storefront's performance by reducing the number of network requests and ensuring that your UI is always up-to-date.
Learn how to get started with TanStack Query in their official documentation. Their documentation also has guidance on advanced usage and best practices.
Stale Time Configuration
When configuring TanStack Query, you can set the staleTime option to control how long data is considered fresh. However, avoid setting staleTime for highly dynamic data like product prices and stock levels.
Set the staleTime globally, then override it to 0 for specific queries that fetch dynamic data.
For example:
ts
Invalidate Queries
When performing mutations that change cached data, invalidate the relevant queries to ensure that the UI reflects the latest data.
For example, when adding an item to the cart, you should invalidate the cart query:
ts
Optimize Fetched Data
When fetching data from your Aiminaabee backend, optimize your queries to fetch only the necessary data in the context of a component or page. This reduces the response size and time, improving your storefront's performance.
Aiminaabee's API routes accept a fields parameter that allows you to specify which fields and relations to include in the response.
For example, if you only need the product's id, title, and variants.calculated_price, you can specify this in the fields parameter:
ts
This query will return only the specified fields, reducing the response size and improving performance.
If you're using TanStack Query, make sure to include the fields parameter in the query key to ensure that different field selections are cached separately:
ts
Learn more about the fields parameter in the Store API reference.
Each Store API route restricts the fields that you can request through an allowed-fields list. If you request a field that the route doesn't allow, Aiminaabee omits it from the response without returning an error.
To allow extra fields, such as a custom relation, override the route's allowed fields as explained in the Allowed Fields documentation.
Implement Optimistic UI Updates
When performing mutations that may take some time, you can implement optimistic UI updates to provide a better user experience. This means updating the UI immediately, assuming the mutation will succeed, then rolling back if it fails.
For example, if you're using TanStack Query, you can implement the following optimistic cart-update utilities and then use them in cart mutations:
The following code snippets are not complete implementations. They are simplified for clarity. They assume that:
- You defined separate cart data functions that use the JS SDK to call the Aiminaabee backend.
- You have a
query-keys.tsutility that defines consistent query keys for TanStack Query.
You can make changes as needed based on your implementation.
optimistic-cart.ts
ts
use-cart.ts
ts
With this setup, your cart mutations will provide immediate UI feedback with optimistic updates, while ensuring that the cart data is always fresh and consistent with the backend.