Skip to main content

ServerFetch Function

The ServerFetch function is a server-side data-fetching function used during Server-Side Rendering (SSR). It allows themes to fetch data, execute FPI APIs, and apply server-side logic before HTML is rendered and sent to the browser. This function runs only on the server and is commonly used for Product Listing Pages (PLP), Product Display Pages (PDP), and other SEO-critical pages.
For example, the ServerFetch implementation for the PLP runs during SSR to fetch product data before the page is rendered. The function also determines the active theme and enables conditional server-side logic or custom API calls based on the theme, while allowing FPI to automatically handle cookie forwarding.

function serverFetch({ fpi, router, cookies, themeId }): Promise<any>

Parameters

ParameterTypeDescription
fpiobjectFPI client instance. Used for store updates and API calls (for example, fpi.executeGQL()).
routerobjectCurrent route and query information. Includes params, filterQuery, etc.
cookiesobjectRequest cookies available during SSR. Contains themeCookie
themeIdstringCurrent theme ID

Cookies in ServerFetch

During SSR, the host passes request cookies into serverFetch.
These cookies can be used for data fetching, conditional logic, or custom API calls.

Theme Cookie represents the theme or mode associated with the current request. With the introduction of cookies.themeCookie, themes can now reliably adapt server-side behavior based on the active theme or mode, while maintaining a clear separation between FPI-managed and custom data flows.
The value of the themeCookie for the current request (for example: dark-mode, light-mode, or a custom theme identifier). Only when the incoming request includes a themeCookie. If not present, the value may be undefined or empty.

Use cookies.themeCookie when you need to:

  • Pass the theme or mode to a non-FPI API (your own backend or a third-party service).
  • Apply conditional logic based on the current theme or mode.
  • Modify request headers, query variables, or server-side behavior per theme.

Key Points to Remember

  • Use cookies.themeCookie only when you need custom server-side logic or non-FPI integrations.
  • FPI APIs automatically include themeCookie in the Cookie header. You do not need to pass it explicitly when using fpi.executeGQL() or other FPI calls.

Example: Product Listing Page (SSR with serverFetch)

This example shows how to use serverFetch for SSR. Data is fetched on the server before the page is rendered, which is ideal for SEO-critical pages.

ProductListing.serverFetch = async ({ fpi, router, cookies, themeId }) => {
// FPI calls automatically include themeCookie in the Cookie header
await fpi.executeGQL(PRODUCT_LISTING_QUERY, {
slug: router.params?.slug,
pageNo: router.filterQuery?.page_no ?? 1,
});

// Use cookies.themeCookie for custom logic or non-FPI APIs
const themeMode = cookies?.themeCookie || 'default';

if (themeMode === 'dark-mode') {
// Example: Call custom API or modify headers based on theme
}
return Promise.resolve();
};

Example: Product Details Page

ProductDescription.serverFetch = async ({ fpi, router, cookies, themeId }) => {
const slug = router?.params?.slug;
if (!slug) {
return Promise.resolve();
}
// FPI/GraphQL calls automatically send themeCookie in the Cookie header
await fpi.executeGQL(PRODUCT_DETAIL_QUERY, {
slug,
id: router?.params?.id,
});
// Optional: use themeCookie for custom logic or non-FPI APIs
const themeMode = cookies?.themeCookie || 'default';
if (themeMode === 'preview') {
// e.g. fetch preview-only data from your API
}
return Promise.resolve();
};

On the client side (for example, inside React components), themeCookie is provided by the host through React context. To access it, use the useClientInfo() hook from fdk-core/utils. Client-side access to themeCookie is done via React context, not serverFetch.

Example

import { useClientInfo } from 'fdk-core/utils';

function ThemeSwitcher() {
const { themeCookie } = useClientInfo();

return <span>Current theme: {themeCookie || 'default'}</span>;
}

Example: Product Listing Page

This example shows a Client-Side Rendering (CSR) approach where data is fetched in the browser after the component mounts. Use this pattern when SEO is not a concern or for interactive pages that don't need server-side data fetching.

import { useEffect } from "react";
import { useGlobalStore } from "fdk-core/utils";

const ProductListing = ({ fpi }) => {
// Store Data is available using useGlobalStore
const productLists = useGlobalStore(fpi.getters.PRODUCTS) || {};

// Fetch data on the client side when component mounts
useEffect(() => {
if (!productLists) {
fpi.products.fetchProducts({});
}
}, [productLists]);

return (
<>
{/* Render UI based on store data */}
</>
);
};

// Note: No serverFetch attached - this is a CSR-only component
export default ProductListing;

Example: Combined SSR + CSR Pattern

You can combine both patterns: use serverFetch for initial SSR and useEffect as a fallback or for CSR. This provides the best of both worlds - SEO benefits from SSR and interactive updates from CSR.

import { useEffect } from "react";
import { useGlobalStore } from "fdk-core/utils";

const ProductListing = ({ fpi }) => {
const productLists = useGlobalStore(fpi.getters.PRODUCTS) || {};

// Fallback: Fetch on client if data wasn't loaded via serverFetch
useEffect(() => {
if (!productLists || Object.keys(productLists).length === 0) {
fpi.products.fetchProducts({});
}
}, [productLists, fpi]);

return (
<>
{/* Render UI based on store data */}
</>
);
};

// SSR: Fetch data on the server before rendering
ProductListing.serverFetch = async ({ fpi, router }) => {
const queries = router.filterQuery;
const defaultQuery = {
pageNo: 1,
pageSize: 12,
...queries,
};
return fpi.products.fetchProductListing(defaultQuery);
};

export default ProductListing;

Example: Register Pages in the Theme Bootstrap

Theme pages must be exported as default components from the pages directory. In the ~/theme/index.jsx file, the page should be returned from within the default exported bootstrap function. To create a separate chunk for the page, developers can use Webpack’s dynamic import() syntax to load the component asynchronously.

note

Ensure the Webpack's ChunkName matches the key for the component in the returned object.

import FPIClient from "fdk-store";
import sections from "./sections";
import Header from "./components/header/header";
import Footer from "./components/footer/footer";

export default async ({
applicationID,
applicationToken,
domain,
storeInitialData,
}) => {
const fpiOptions = {
applicationID,
applicationToken,
domain,
storeInitialData,
};

const { client: fpi } = new FPIClient(fpiOptions);

return {
fpi,
sections,
getHeader: () => Header,
getFooter: () => Footer,
getProductListing: () =>
import(
/* webpackChunkName:"getProductListing" */ "./pages/product-listing"
),
};
};