Skip to main content
Studio edits a Next.js storefront through two pieces that work together:
  1. A root-level script connector that loads the Next Studio bridge when the storefront runs inside Studio.
  2. A page-level runtime binding that connects the rendered page to Studio’s editor.
On top of those, a few app-owned pieces make editing complete: the route identity each page reports, a revalidation route for resource pickers, and the theme’s own routes so Studio opens the right URLs.

Mount the Studio connector once

Mount WeaverseNextStudioConnect in the root layout. It loads the bridge script in design, preview and revision contexts and does nothing in published mode.
Mount it in the root layout, not per page. The layout also renders around routes that never render a Weaverse page, such as not-found.tsx and error.tsx, and Studio needs the bridge before a page tree exists. It is SSR-safe: the component only touches document inside an effect.

Page binding comes with the renderer

WeaverseNextRenderer creates and binds the page runtime; you don’t wire it yourself. It maps Studio’s internals onto the App Router: Both the connector and the renderer are required for full editing. See Rendering Pages for the client boundary that renders WeaverseNextRenderer.

Report the route identity

Studio attaches to the route the page says it is. The server client’s request context carries that identity, and it travels to the browser in configs.requestInfo:
On the client, restore the same identity from the payload when you create the client. If the client’s request context is empty, the page renders but Studio has nothing to outline. Rendering Pages shows the full client boundary. For localized storefronts, set i18n from the request’s market. See Markets & Translations.

Design mode

When Studio loads the storefront, it adds isDesignMode=true to the URL. The server client reads it from the request context (or the search params) and:
  • reads page and theme data with cache: 'no-store' in design and revision preview, so edits are never served from cache;
  • returns isDesignMode, isPreviewMode and isRevisionPreview in the page payload’s configs.
To branch on it in a route, read the search param:
On the client, read it from the request context restored from configs. For shared patterns, see Studio vs. Live Environment.

Per-item revalidation

When a merchant changes a resource picker (a product, a collection), Studio asks the storefront to re-run that one component’s loader with the draft settings. Without this route, the edit shows stale data until a full reload. Mount the handler at app/api/weaverse/revalidate/route.ts:
getClient receives the validated route context reconstructed from the request body, so the loader re-runs with the live page’s pathname, locale, page type and handle rather than the endpoint’s own path. createWeaverseServerClientFromContext is your app’s helper that builds the server client from a context; see Data Fetching. The flow:
If the route is missing or fails, Studio falls back to refreshing the whole route.

Trust boundary

The endpoint is public, and every field in the body is attacker-controlled. The handler re-validates it independently:
  • Only pathname, a sanitized search, a narrow i18n subset, a valid pageType and a bounded handle cross the boundary. Headers, cookies, env, project ID and Studio host are never read from the body.
  • Server configuration (weaverseProjectId, weaverseHost, API base and similar) is stripped from the body. Project ID, host and env always come from your server config.
  • The origin is fixed from the endpoint request, so the body cannot change protocol, host or port.
  • A malformed routeContext returns 400 { error: 'invalid-route-context' } before getClient runs.
The route context is routing input, never an authorization decision. A loader must not treat a pathname, handle, page type or locale as proof of access. Customer or private data still needs its own server-side session and authorization checks.

Theme routes

Studio’s page selector and URL picker build Shopify-style paths by default: /collections/:handle, /blogs/:blog/:handle. If your storefront routes differently, declare routes in the theme schema so Studio opens your own paths:
  • A pattern is an absolute path of static segments and whole :param segments.
  • :handle is the page’s own handle (product, collection, page, blog or article). :blog is an article’s blog handle.
  • Declare only the routes that differ from the Shopify convention. Studio uses the convention for every key you leave out, and for a pattern it cannot fill.
  • CUSTOM pages carry their own path and cannot take a pattern.
The schema’s routes key is typed as ThemeRoutes. Studio reads routes from the theme schema the preview sends in design mode, starting with release 2026.10.22.
Keep each declared route on a route your app actually serves. A test that checks every routes value against your route files catches a renamed route before Studio does.

Default resources

To open the default product, collection or page template, Studio looks up a store resource with your public Storefront API credentials, PUBLIC_STORE_DOMAIN and PUBLIC_STOREFRONT_API_TOKEN, from the theme’s publicEnv. Without them, the page selector cannot open those templates. Pass publicEnv from the layout to the client WeaverseRoot wrapper from the Quickstart, which hands it to WeaverseNextRootProvider:
loadThemeSettings() returns publicEnv only in design mode, which it detects from ?isDesignMode=true. A Next.js layout receives no search params, so the root layout’s response never carries it; pass publicEnv explicitly as above. Only pass the public token: the private Storefront token must never reach the browser.

Usage tracking

There is nothing to wire. @weaverse/next sends no browser pixel; Weaverse counts published (non-design) page responses on the server.

Troubleshooting

For connection errors shared with React Router storefronts, see Preview Connection Errors.
The runtime passes data-wv-id, data-wv-type and related props to every component. Spread them onto the component’s outermost DOM element; otherwise the component renders but has no outline entry or click target.
The client was created without the route identity. Restore pathname, pageType, handle, i18n and the design flags from data.configs.requestInfo when you call createWeaverseNextClient. See Rendering Pages.
Studio could not resolve a default resource. Pass PUBLIC_STORE_DOMAIN and PUBLIC_STOREFRONT_API_TOKEN in publicEnv to WeaverseNextRootProvider (Default resources).
The revalidation route is missing or failing. Add app/api/weaverse/revalidate/route.ts (Per-item revalidation) and check that the component is registered with its loader on the server.
The request context has no pathname. Weaverse resolves CUSTOM pages by pathname and falls back to / without one. Pass the route’s own path when you build the server client.
Declare the theme’s routes in the theme schema.

Next steps

Rendering Pages

Load and render Weaverse pages in App Router routes.

Data Fetching

Component loaders, caching and the server client.

Markets & Translations

Localized routes, market context and theme copy.

API Reference

Every export of @weaverse/next and @weaverse/next/server.