@techsio/storefront-data
setup-storefront-platform-in-next-app
frameworkreactLoad this skill when wiring @techsio/storefront-data into a Next.js App Router storefront through createMedusaStorefrontPreset, StorefrontDataProvider, createMedusaSdk, createLocalStorageValueStore, and explicit subpath imports. Use it for the app-level composition module, provider placement, browser storage seams, and avoiding package-root or ad-hoc preset wiring.
Setup storefront platform in Next app
Setup
Use one thin storefront composition module, one app-level provider boundary, and explicit file-level imports.
// next.config.mjs
const nextConfig = {
transpilePackages: ["@techsio/storefront-data"],
}
export default nextConfig// src/lib/storefront.ts
import { createMedusaSdk } from "@techsio/storefront-data/shared/medusa-client"
import { createLocalStorageValueStore } from "@techsio/storefront-data/shared/storage-value-store"
import { createMedusaStorefrontPreset } from "@techsio/storefront-data/medusa/preset"
const sdk = createMedusaSdk({
baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? "http://localhost:9000",
publishableKey: process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? "",
})
const cartStorage = createLocalStorageValueStore({
key: "shop-cart-id",
})
export const storefront = createMedusaStorefrontPreset({
sdk,
queryKeyNamespace: "shop",
cart: {
hooks: {
cartStorage,
},
},
})// app/providers.tsx
"use client"
import type { PropsWithChildren } from "react"
import { StorefrontDataProvider } from "@techsio/storefront-data/client/provider"
export function Providers({ children }: PropsWithChildren) {
return <StorefrontDataProvider>{children}</StorefrontDataProvider>
}Hooks and Components
Expose only the preset surface the app actually needs
// src/lib/storefront-surface.ts
import { storefront } from "@/src/lib/storefront"
export const { auth, cart, catalog, checkout, collections, products, regions } =
storefront.hooks
export const { cart: cartFlow, checkout: checkoutFlow } = storefront.flowsKeep this layer thin. SDK config, local field defaults, address adapters, and storefront-specific policy belong here. Query keys, services, hooks, and flows stay owned by the preset.
Pass a stable browser QueryClient only when the app really needs overrides
// app/providers.tsx
"use client"
import type { PropsWithChildren } from "react"
import { StorefrontDataProvider } from "@techsio/storefront-data/client/provider"
import { getQueryClient } from "@techsio/storefront-data/shared/query-client"
const client = getQueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
})
export function Providers({ children }: PropsWithChildren) {
return <StorefrontDataProvider client={client}>{children}</StorefrontDataProvider>
}If the app does not need browser-client overrides, keep the provider as <StorefrontDataProvider>{children}</StorefrontDataProvider>.
Common Mistakes
CRITICAL Package-root imports
Wrong:
import { StorefrontDataProvider } from "@techsio/storefront-data"Correct:
import { StorefrontDataProvider } from "@techsio/storefront-data/client/provider"
import { createMedusaStorefrontPreset } from "@techsio/storefront-data/medusa/preset"The root export is intentionally disabled. Treat explicit subpaths as the supported public surface.
Source: libs/storefront-data/package.json, libs/storefront-data/README.md
HIGH Ad-hoc hook assembly instead of a preset
Wrong:
const products = createProductHooks({ service, queryKeyNamespace: "shop" })
const cart = createCartHooks({ service, queryKeyNamespace: "shop" })Correct:
const storefront = createMedusaStorefrontPreset({
sdk,
queryKeyNamespace: "shop",
})The current architecture expects one preset to own hooks, services, query keys, cache semantics, and flow wrappers for a storefront.
Source: libs/storefront-data/README.md, libs/storefront-data/src/medusa/preset.ts
CRITICAL Server helpers inside client code
Wrong:
"use client"
import { getServerQueryClient } from "@techsio/storefront-data/server/get-query-client"Correct:
"use client"
import { StorefrontDataProvider } from "@techsio/storefront-data/client/provider"server/get-query-client guards against client usage because its request-scoped behavior only makes sense on the server.
Source: libs/storefront-data/src/server/get-query-client.ts
HIGH Late provider config changes rebuild the browser client
Wrong:
<StorefrontDataProvider clientConfig={{ defaultOptions: { queries: { staleTime: 0 } } }}>
{children}
</StorefrontDataProvider>Correct:
const client = getQueryClient({
defaultOptions: { queries: { staleTime: 0 } },
})
<StorefrontDataProvider client={client}>{children}</StorefrontDataProvider>The internal browser QueryClient is a singleton. Only the first internal initialization sees clientConfig.
Source: libs/storefront-data/src/client/provider.tsx, libs/storefront-data/src/shared/query-client.ts
See also: implement-ssr-prefetch-and-query-client-boundaries for server-side hydration and query-client ownership.