🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

next-shopify-experimental

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

next-shopify-experimental

Experimental Shopify toolkit for Next.js: a typed Storefront API client, automatic cache tagging, and webhook-driven revalidation.

latest
Source
npmnpm
Version
0.0.3
Version published
Maintainers
1
Created
Source

next-shopify-experimental

npm version npm downloads

A Shopify toolkit for Next.js: a typed Storefront API client with built in support for Next.js 16 Cache Components.

Requirements

  • Next.js 16+ with Cache Components enabled (cacheComponents: true)
  • React 19
  • A Shopify store with a Storefront API access token, plus a webhook signing secret for revalidation

Installation

npm install next-shopify-experimental
# or
pnpm add next-shopify-experimental
# or
yarn add next-shopify-experimental
# or
bun add next-shopify-experimental

Quick start

1. Enable Cache Components

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheComponents: true,
}

export default nextConfig

2. Create the client and a cached fetch

// lib/shopify.ts
import { createStorefrontClient } from 'next-shopify-experimental'
import { defineFetch } from 'next-shopify-experimental/cache'

// Reads SHOPIFY_STORE_DOMAIN + SHOPIFY_STOREFRONT_TOKEN from the environment.
export const { shopifyFetch } = defineFetch({
  client: createStorefrontClient(),
})

createStorefrontClient() reads your store domain and access token from the environment by convention, so the common case takes no arguments. Pass any option to override its env default, and it validates up front — a missing domain or token throws a clear, actionable error instead of failing cryptically on the first request.

3. Read data inside a 'use cache' boundary

shopifyFetch runs the query, then tags the surrounding cache entry with the GID of every resource it returned. Call it from a 'use cache' function:

// app/page.tsx
import { shopifyFetch } from '@/lib/shopify'

async function getShop() {
  'use cache'
  const { data } = await shopifyFetch<{ shop: { id: string; name: string } }>({
    query: `{ shop { id name } }`,
  })
  return data?.shop
}

export default async function Page() {
  const shop = await getShop()
  return <h1>{shop?.name}</h1>
}

4. Revalidate on change with a webhook

Add a webhook route. When Shopify reports a change, next-shopify-experimental verifies it and revalidates the matching tags:

// app/api/shopify/webhook/route.ts
export { POST } from 'next-shopify-experimental/webhook'

Then create a webhook subscription pointed at https://your-app.com/api/shopify/webhook, and set its signing secret as SHOPIFY_WEBHOOK_SECRET.

5. Set environment variables

# .env.local
SHOPIFY_STORE_DOMAIN=your-shop.myshopify.com
SHOPIFY_STOREFRONT_TOKEN=your-public-storefront-access-token
SHOPIFY_WEBHOOK_SECRET=your-webhook-signing-secret
VariableRead byDescription
SHOPIFY_STORE_DOMAINcreateStorefrontClientYour store's domain.
SHOPIFY_STOREFRONT_TOKENcreateStorefrontClientA public Storefront API access token.
SHOPIFY_WEBHOOK_SECRETthe webhook handlerThe webhook signing secret — read automatically by POST.

createStorefrontClient also reads SHOPIFY_STOREFRONT_PRIVATE_TOKEN (a server-only token, as an alternative to the public one) and SHOPIFY_API_VERSION (optional; otherwise a built-in default is used).

That's the whole integration: reads are cached and tagged, and a shop/update webhook busts exactly the pages that read the shop.

How it works

Every object in Shopify's API has a global ID — a GID, like gid://shopify/Shop/1. next-shopify-experimental uses it as the link between reads and writes:

  • On read, shopifyFetch scans the response for GIDs and tags the cache entry with each one (shopify:shop:1).
  • On write, your webhook receives the same GID, resolves it to the same tag, and calls revalidateTag.

Because both sides derive the tag from the same GID, a change invalidates exactly the cache entries that read that resource — with no tag bookkeeping on your part.

API reference

createStorefrontClient

Creates the Storefront API client, reading configuration from the environment by convention so the common case is zero-argument. It validates up front — a missing store domain or access token throws a clear, actionable error rather than failing cryptically on the first request. Pass any option to override its env default.

import { createStorefrontClient } from 'next-shopify-experimental'

// Reads SHOPIFY_STORE_DOMAIN + SHOPIFY_STOREFRONT_TOKEN from the environment:
const client = createStorefrontClient()

// …or override any option:
const client = createStorefrontClient({ apiVersion: '2025-10' })

Every option is optional; each falls back to an environment variable:

OptionFalls back toDescription
storeDomainSHOPIFY_STORE_DOMAINYour *.myshopify.com (or custom) domain.
publicAccessTokenSHOPIFY_STOREFRONT_TOKENA public Storefront access token (safe in the browser).
privateAccessTokenSHOPIFY_STOREFRONT_PRIVATE_TOKENA private Storefront access token (server only).
apiVersionSHOPIFY_API_VERSION (or default)Storefront API version, e.g. '2026-04'.

A store domain and exactly one access token are required (from config or the environment). It also accepts the client's remaining options (clientName, retries, customFetchApi, logger).

createStorefrontApiClient

The raw client factory, re-exported from @shopify/storefront-api-client (along with all of its types) unchanged — no env convention, no validation. Reach for it when you want full, unmanaged control; otherwise prefer createStorefrontClient. request() is return-based and does not throw on GraphQL errors.

import { createStorefrontApiClient } from 'next-shopify-experimental'

const client = createStorefrontApiClient({
  storeDomain: 'your-shop.myshopify.com',
  apiVersion: '2026-04',
  publicAccessToken: process.env.SHOPIFY_STOREFRONT_TOKEN!,
})

defineFetch

From next-shopify-experimental/cache. Binds a client to a shopifyFetch that tags reads for revalidation.

import { defineFetch } from 'next-shopify-experimental/cache'

export const { shopifyFetch } = defineFetch({ client })
NameTypeDefaultDescription
clientStorefrontApiClientThe client returned by createStorefrontApiClient.
debugbooleanfalseLog each fetch's collected cache tags to the server console.

shopifyFetch

Returns the client's { data, errors, extensions } response, and tags the surrounding 'use cache' entry.

const { data, errors } = await shopifyFetch<TData>({ query, variables })
NameTypeDefaultDescription
querystringThe GraphQL operation.
variablesobjectOperation variables.
cachebooleantrueTag this read. Set false for a dynamic, uncached read — no 'use cache' boundary needed.
debugbooleaninheritedOverride the defineFetch debug setting for this call.

It also accepts the underlying client's request options (apiVersion, headers, retries, signal).

Inside a 'use cache' boundary, shopifyFetch tags the entry. Called outside one without cache: false, it throws with a message pointing you at both fixes.

next-shopify-experimental/webhook

POST

The convention handler — verifies with SHOPIFY_WEBHOOK_SECRET and revalidates. Re-export it as your route:

// app/api/shopify/webhook/route.ts
export { POST } from 'next-shopify-experimental/webhook'

createWebhookHandler

Use the factory when you need to configure it:

import { createWebhookHandler } from 'next-shopify-experimental/webhook'

export const POST = createWebhookHandler({
  secret: process.env.SHOPIFY_WEBHOOK_SECRET,
})
NameTypeDefaultDescription
secretstringprocess.env.SHOPIFY_WEBHOOK_SECRETWebhook signing secret. The handler fails closed (500) if it's missing.
signatureVerificationbooleantrueSet false only if you verify upstream — HMAC is skipped and no secret is required.

Responses: 200 { revalidated } for a verified webhook (including topics it doesn't tag), 401 for a missing or invalid signature, 500 if the secret isn't configured.

Primitives

To build a fully custom handler, compose these directly:

ExportDescription
verifyWebhook({ body, signature, secret })Verify a Shopify webhook signature (Web Crypto, constant-time). Resolves a boolean; never throws.
getWebhookCacheTags(topic, payload)Derive the cache tags for a verified payload — the same tags the read side produced.

Supported resources

next-shopify-experimental tags the Shop resource today. Other resources (products, collections, …) aren't tagged yet: their data still reads normally, but no tags are emitted for them and their webhooks are acknowledged without revalidation — no errors are thrown. Coverage grows as the resource registry expands.

Local example

A runnable Next.js app lives in apps/example.

License

MIT

Keywords

next

FAQs

Package last updated on 04 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts