Skip to main content

Data Fetching in Next.js

A section can resolve its own data on the server with a loader, exactly as with @weaverse/hydrogen on React Router: the loader runs during the page load, and its result reaches the component as loaderData. What changes in Next.js is where loaders live, what they receive, and how caching works. This is the Next.js counterpart of Section Data Fetching. Schemas and inputs are shared; see Component Schema and Input Settings.

Where loaders live

Next.js splits code into Server and Client Components. WeaverseNextRenderer is a Client Component, so every composable section is too, and a Client Component module cannot import server-only code. Keep two registries with the same schemas: The client registry goes to createWeaverseNextClient; the server registry goes to createWeaverseNextServerClient. The server registry never renders, so its default is a stub. This is Forward’s, trimmed:
Do not import the client registry from the server one, or the reverse. The first drags every section into the server graph; the second ships your loaders, queries and credentials to the browser.

Writing a loader

A loader receives one argument, WeaverseNextComponentLoaderArgs: It returns any serializable value, which the component receives as the loaderData prop. This is Forward’s featured-products loader. The merchant picks products in Studio; the loader resolves them in the request’s market:
The component reads loaderData and renders a placeholder while nothing is picked:
Spread the remaining props onto the section’s root element. They carry the data-wv-* attributes Studio uses to outline and select the item; without them the section renders but cannot be edited.

The commerce context

Weaverse never owns your Shopify client. Pass one to the server client as commerce, and loaders receive it:
A loader then queries through it:
storefront is the only member the SDK reads. Cart, customer account and other services can ride along on commerce; the SDK passes them through untouched. Forward skips commerce and calls its own server-only data layer from loaders, which is equally valid: a loader is ordinary server code.

Scope reads to the market

A loader runs for one market. Read it from context.i18n (the Storefront language and country), not from a global default, so a localized page shows localized products and prices. Per-item revalidation passes the same i18n, so the loader resolves the same market when a merchant edits the section. See Markets & Translations.

Revalidating when settings change

A resource input with shouldRevalidate: true re-runs the item’s loader when the merchant changes it in Studio:
In Next.js this goes through your revalidation route handler: Studio posts the draft item, the handler re-runs that one loader with the live page’s route identity, and the SDK applies the new loaderData in place, without refreshing the whole page. Set up the route in Studio Integration.

Caching

The server client fetches from Weaverse with Next’s fetch cache.
  • Default cache for the client: cache: { revalidate, tags } on createWeaverseNextServerClient maps to fetch(..., { next: { revalidate, tags } }). revalidate: false caches indefinitely.
  • Per request: weaverse.fetchWithCache(url, { revalidate, tags, ...init }) is the same helper for your own Weaverse API calls, and overrides the client defaults.
  • Studio is never stale: in design mode and revision preview, every Weaverse read is forced to cache: 'no-store', whatever you configured.
Your own Shopify reads are cached by whatever client you use. Route freshness is ordinary Next config:
Use tags with Next’s revalidateTag to purge Weaverse data on demand.

Differences from React Router loaders

Next steps

Rendering Pages

Route identity, page types and route-owned data

Studio Integration

Set up per-item revalidation

Markets & Translations

Locale-aware loaders and routes

API Reference

WeaverseNextComponentLoaderArgs and friends